summaryrefslogtreecommitdiffstats
path: root/usr
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--usr/.gitignore2
-rw-r--r--usr/Kbuild75
-rw-r--r--usr/dash/.gitignore13
-rw-r--r--usr/dash/Kbuild103
-rw-r--r--usr/dash/README.dash50
-rw-r--r--usr/dash/TOUR343
-rw-r--r--usr/dash/alias.c227
-rw-r--r--usr/dash/alias.h52
-rw-r--r--usr/dash/arith_yacc.c304
-rw-r--r--usr/dash/arith_yacc.h89
-rw-r--r--usr/dash/arith_yylex.c240
-rw-r--r--usr/dash/bltin/bltin.h89
-rw-r--r--usr/dash/bltin/echo.1109
-rw-r--r--usr/dash/bltin/printf.1354
-rw-r--r--usr/dash/bltin/printf.c470
-rw-r--r--usr/dash/bltin/test.1309
-rw-r--r--usr/dash/bltin/test.c543
-rw-r--r--usr/dash/builtins.def.in93
-rw-r--r--usr/dash/cd.c313
-rw-r--r--usr/dash/cd.h35
-rw-r--r--usr/dash/config.h191
-rw-r--r--usr/dash/error.c232
-rw-r--r--usr/dash/error.h133
-rw-r--r--usr/dash/eval.c1092
-rw-r--r--usr/dash/eval.h59
-rw-r--r--usr/dash/exec.c859
-rw-r--r--usr/dash/exec.h77
-rw-r--r--usr/dash/expand.c1728
-rw-r--r--usr/dash/expand.h88
-rw-r--r--usr/dash/funcs/cmv47
-rw-r--r--usr/dash/funcs/dirs71
-rw-r--r--usr/dash/funcs/kill47
-rw-r--r--usr/dash/funcs/login36
-rw-r--r--usr/dash/funcs/newgrp35
-rw-r--r--usr/dash/funcs/popd71
-rw-r--r--usr/dash/funcs/pushd71
-rw-r--r--usr/dash/funcs/suspend39
-rwxr-xr-xusr/dash/gendeps.pl38
-rw-r--r--usr/dash/hetio.c397
-rw-r--r--usr/dash/hetio.h22
-rw-r--r--usr/dash/histedit.c494
-rw-r--r--usr/dash/init.h39
-rw-r--r--usr/dash/input.c532
-rw-r--r--usr/dash/input.h66
-rw-r--r--usr/dash/jobs.c1504
-rw-r--r--usr/dash/jobs.h109
-rw-r--r--usr/dash/machdep.h53
-rw-r--r--usr/dash/mail.c112
-rw-r--r--usr/dash/mail.h38
-rw-r--r--usr/dash/main.c346
-rw-r--r--usr/dash/main.h54
-rw-r--r--usr/dash/memalloc.c302
-rw-r--r--usr/dash/memalloc.h100
-rw-r--r--usr/dash/miscbltin.c583
-rw-r--r--usr/dash/miscbltin.h31
-rw-r--r--usr/dash/mkbuiltins115
-rw-r--r--usr/dash/mkinit.c479
-rw-r--r--usr/dash/mknodes.c448
-rw-r--r--usr/dash/mksyntax.c315
-rw-r--r--usr/dash/mktokens92
-rw-r--r--usr/dash/myhistedit.h45
-rw-r--r--usr/dash/mystring.c257
-rw-r--r--usr/dash/mystring.h63
-rw-r--r--usr/dash/nodes.c.pat166
-rw-r--r--usr/dash/nodetypes151
-rw-r--r--usr/dash/options.c559
-rw-r--r--usr/dash/options.h86
-rw-r--r--usr/dash/output.c399
-rw-r--r--usr/dash/output.h123
-rw-r--r--usr/dash/parser.c1568
-rw-r--r--usr/dash/parser.h93
-rw-r--r--usr/dash/redir.c459
-rw-r--r--usr/dash/redir.h53
-rw-r--r--usr/dash/sh.12332
-rw-r--r--usr/dash/shell.h104
-rw-r--r--usr/dash/show.c406
-rw-r--r--usr/dash/show.h45
-rw-r--r--usr/dash/system.c199
-rw-r--r--usr/dash/system.h101
-rw-r--r--usr/dash/trap.c467
-rw-r--r--usr/dash/trap.h58
-rw-r--r--usr/dash/var.c710
-rw-r--r--usr/dash/var.h173
-rw-r--r--usr/gzip/.gitignore3
-rw-r--r--usr/gzip/COPYING339
-rw-r--r--usr/gzip/Kbuild26
-rw-r--r--usr/gzip/README144
-rw-r--r--usr/gzip/bits.c200
-rw-r--r--usr/gzip/deflate.c759
-rw-r--r--usr/gzip/gzip.c1215
-rw-r--r--usr/gzip/gzip.h298
-rw-r--r--usr/gzip/inflate.c950
-rw-r--r--usr/gzip/revision.h11
-rw-r--r--usr/gzip/tailor.h50
-rw-r--r--usr/gzip/trees.c1075
-rw-r--r--usr/gzip/unzip.c77
-rw-r--r--usr/gzip/util.c372
-rw-r--r--usr/gzip/zip.c110
-rw-r--r--usr/include/Kbuild11
-rw-r--r--usr/include/alloca.h12
-rw-r--r--usr/include/arch/alpha/klibc/archconfig.h16
-rw-r--r--usr/include/arch/alpha/klibc/archsetjmp.h33
-rw-r--r--usr/include/arch/alpha/klibc/archsignal.h88
-rw-r--r--usr/include/arch/alpha/machine/asm.h44
-rw-r--r--usr/include/arch/arm/klibc/archconfig.h18
-rw-r--r--usr/include/arch/arm/klibc/archsetjmp.h14
-rw-r--r--usr/include/arch/arm/klibc/archsignal.h122
-rw-r--r--usr/include/arch/arm/klibc/asmmacros.h16
-rw-r--r--usr/include/arch/arm64/klibc/archconfig.h15
-rw-r--r--usr/include/arch/arm64/klibc/archsetjmp.h22
-rw-r--r--usr/include/arch/arm64/klibc/archsignal.h14
-rw-r--r--usr/include/arch/i386/klibc/archconfig.h15
-rw-r--r--usr/include/arch/i386/klibc/archinit.h18
-rw-r--r--usr/include/arch/i386/klibc/archsetjmp.h19
-rw-r--r--usr/include/arch/i386/klibc/archsignal.h75
-rw-r--r--usr/include/arch/i386/klibc/diverr.h15
-rw-r--r--usr/include/arch/i386/sys/io.h127
-rw-r--r--usr/include/arch/i386/sys/vm86.h40
-rw-r--r--usr/include/arch/ia64/klibc/archconfig.h20
-rw-r--r--usr/include/arch/ia64/klibc/archsetjmp.h17
-rw-r--r--usr/include/arch/ia64/klibc/archsignal.h32
-rw-r--r--usr/include/arch/loongarch64/klibc/archconfig.h15
-rw-r--r--usr/include/arch/loongarch64/klibc/archsetjmp.h26
-rw-r--r--usr/include/arch/loongarch64/klibc/archsignal.h14
-rw-r--r--usr/include/arch/loongarch64/machine/asm.h24
-rw-r--r--usr/include/arch/m68k/klibc/archconfig.h15
-rw-r--r--usr/include/arch/m68k/klibc/archsetjmp.h26
-rw-r--r--usr/include/arch/m68k/klibc/archsignal.h74
-rw-r--r--usr/include/arch/mips/klibc/archconfig.h21
-rw-r--r--usr/include/arch/mips/klibc/archfcntl.h107
-rw-r--r--usr/include/arch/mips/klibc/archsetjmp.h25
-rw-r--r--usr/include/arch/mips/klibc/archsignal.h14
-rw-r--r--usr/include/arch/mips/klibc/archsocket.h17
-rw-r--r--usr/include/arch/mips/machine/asm.h76
-rw-r--r--usr/include/arch/mips/sgidefs.h20
-rw-r--r--usr/include/arch/mips/spaces.h1
-rw-r--r--usr/include/arch/mips64/klibc/archconfig.h20
-rw-r--r--usr/include/arch/mips64/klibc/archsetjmp.h25
-rw-r--r--usr/include/arch/mips64/klibc/archsignal.h14
-rw-r--r--usr/include/arch/mips64/klibc/archsocket.h17
-rw-r--r--usr/include/arch/mips64/machine/asm.h82
-rw-r--r--usr/include/arch/parisc/klibc/archconfig.h14
-rw-r--r--usr/include/arch/parisc/klibc/archsetjmp.h14
-rw-r--r--usr/include/arch/parisc/klibc/archsignal.h25
-rw-r--r--usr/include/arch/ppc/klibc/archconfig.h12
-rw-r--r--usr/include/arch/ppc/klibc/archsetjmp.h36
-rw-r--r--usr/include/arch/ppc/klibc/archsignal.h14
-rw-r--r--usr/include/arch/ppc64/klibc/archconfig.h10
-rw-r--r--usr/include/arch/ppc64/klibc/archsetjmp.h36
-rw-r--r--usr/include/arch/ppc64/klibc/archsignal.h14
-rw-r--r--usr/include/arch/riscv64/klibc/archconfig.h15
-rw-r--r--usr/include/arch/riscv64/klibc/archsetjmp.h27
-rw-r--r--usr/include/arch/riscv64/klibc/archsignal.h14
-rw-r--r--usr/include/arch/riscv64/machine/asm.h26
-rw-r--r--usr/include/arch/s390/klibc/archconfig.h20
-rw-r--r--usr/include/arch/s390/klibc/archsetjmp.h26
-rw-r--r--usr/include/arch/s390/klibc/archsignal.h76
-rw-r--r--usr/include/arch/sh/klibc/archconfig.h12
-rw-r--r--usr/include/arch/sh/klibc/archsetjmp.h22
-rw-r--r--usr/include/arch/sh/klibc/archsignal.h14
-rw-r--r--usr/include/arch/sparc/klibc/archconfig.h19
-rw-r--r--usr/include/arch/sparc/klibc/archsetjmp.h16
-rw-r--r--usr/include/arch/sparc/klibc/archsignal.h17
-rw-r--r--usr/include/arch/sparc/machine/asm.h202
-rw-r--r--usr/include/arch/sparc/machine/frame.h146
-rw-r--r--usr/include/arch/sparc/machine/trap.h140
-rw-r--r--usr/include/arch/sparc64/klibc/archconfig.h15
-rw-r--r--usr/include/arch/sparc64/klibc/archsetjmp.h16
-rw-r--r--usr/include/arch/sparc64/klibc/archsignal.h17
-rw-r--r--usr/include/arch/sparc64/machine/asm.h1
-rw-r--r--usr/include/arch/sparc64/machine/frame.h1
-rw-r--r--usr/include/arch/x86_64/klibc/archconfig.h15
-rw-r--r--usr/include/arch/x86_64/klibc/archsetjmp.h21
-rw-r--r--usr/include/arch/x86_64/klibc/archsignal.h64
-rw-r--r--usr/include/arch/x86_64/sys/io.h127
-rw-r--r--usr/include/arpa/inet.h22
-rw-r--r--usr/include/assert.h28
-rw-r--r--usr/include/bits32/bitsize.h3
-rw-r--r--usr/include/bits32/bitsize/limits.h14
-rw-r--r--usr/include/bits32/bitsize/stdint.h34
-rw-r--r--usr/include/bits32/bitsize/stdintconst.h18
-rw-r--r--usr/include/bits32/bitsize/stdintlimits.h23
-rw-r--r--usr/include/bits64/bitsize.h3
-rw-r--r--usr/include/bits64/bitsize/limits.h14
-rw-r--r--usr/include/bits64/bitsize/stdint.h34
-rw-r--r--usr/include/bits64/bitsize/stdintconst.h18
-rw-r--r--usr/include/bits64/bitsize/stdintlimits.h23
-rw-r--r--usr/include/byteswap.h15
-rw-r--r--usr/include/ctype.h174
-rw-r--r--usr/include/dirent.h43
-rw-r--r--usr/include/elf.h11
-rw-r--r--usr/include/endian.h21
-rw-r--r--usr/include/errno.h13
-rw-r--r--usr/include/fcntl.h67
-rw-r--r--usr/include/fnmatch.h15
-rw-r--r--usr/include/getopt.h22
-rw-r--r--usr/include/grp.h22
-rw-r--r--usr/include/inttypes.h226
-rw-r--r--usr/include/klibc/compiler.h158
-rw-r--r--usr/include/klibc/diverr.h15
-rw-r--r--usr/include/klibc/endian.h39
-rw-r--r--usr/include/klibc/extern.h16
-rw-r--r--usr/include/klibc/seek.h14
-rw-r--r--usr/include/klibc/sysconfig.h235
-rw-r--r--usr/include/limits.h47
-rw-r--r--usr/include/malloc.h22
-rw-r--r--usr/include/mntent.h21
-rw-r--r--usr/include/net/if.h8
-rw-r--r--usr/include/net/if_arp.h3
-rw-r--r--usr/include/net/if_packet.h2
-rw-r--r--usr/include/net/route.h2
-rw-r--r--usr/include/netinet/if_ether.h2
-rw-r--r--usr/include/netinet/in.h38
-rw-r--r--usr/include/netinet/in6.h11
-rw-r--r--usr/include/netinet/ip.h13
-rw-r--r--usr/include/netinet/tcp.h11
-rw-r--r--usr/include/netinet/udp.h19
-rw-r--r--usr/include/netpacket/packet.h2
-rw-r--r--usr/include/paths.h74
-rw-r--r--usr/include/poll.h1
-rw-r--r--usr/include/pwd.h21
-rw-r--r--usr/include/sched.h39
-rw-r--r--usr/include/setjmp.h48
-rw-r--r--usr/include/signal.h103
-rw-r--r--usr/include/stdarg.h14
-rw-r--r--usr/include/stddef.h54
-rw-r--r--usr/include/stdint.h116
-rw-r--r--usr/include/stdio.h156
-rw-r--r--usr/include/stdlib.h104
-rw-r--r--usr/include/string.h49
-rw-r--r--usr/include/sys/auxv.h17
-rw-r--r--usr/include/sys/capability.h11
-rw-r--r--usr/include/sys/dirent.h32
-rw-r--r--usr/include/sys/elf32.h117
-rw-r--r--usr/include/sys/elf64.h117
-rw-r--r--usr/include/sys/elfcommon.h202
-rw-r--r--usr/include/sys/file.h9
-rw-r--r--usr/include/sys/fsuid.h14
-rw-r--r--usr/include/sys/inotify.h16
-rw-r--r--usr/include/sys/ioctl.h18
-rw-r--r--usr/include/sys/klog.h24
-rw-r--r--usr/include/sys/md.h34
-rw-r--r--usr/include/sys/mman.h26
-rw-r--r--usr/include/sys/mount.h71
-rw-r--r--usr/include/sys/param.h11
-rw-r--r--usr/include/sys/poll.h20
-rw-r--r--usr/include/sys/prctl.h11
-rw-r--r--usr/include/sys/reboot.h25
-rw-r--r--usr/include/sys/resource.h48
-rw-r--r--usr/include/sys/select.h17
-rw-r--r--usr/include/sys/sendfile.h14
-rw-r--r--usr/include/sys/socket.h270
-rw-r--r--usr/include/sys/splice.h19
-rw-r--r--usr/include/sys/stat.h96
-rw-r--r--usr/include/sys/statfs.h1
-rw-r--r--usr/include/sys/syscall.h13
-rw-r--r--usr/include/sys/sysconf.h40
-rw-r--r--usr/include/sys/sysinfo.h13
-rw-r--r--usr/include/sys/sysmacros.h37
-rw-r--r--usr/include/sys/time.h117
-rw-r--r--usr/include/sys/times.h14
-rw-r--r--usr/include/sys/types.h108
-rw-r--r--usr/include/sys/uio.h15
-rw-r--r--usr/include/sys/un.h11
-rw-r--r--usr/include/sys/utime.h11
-rw-r--r--usr/include/sys/utsname.h23
-rw-r--r--usr/include/sys/vfs.h132
-rw-r--r--usr/include/sys/wait.h28
-rw-r--r--usr/include/sysexits.h26
-rw-r--r--usr/include/syslog.h62
-rw-r--r--usr/include/termios.h91
-rw-r--r--usr/include/time.h18
-rw-r--r--usr/include/unistd.h167
-rw-r--r--usr/include/utime.h14
-rw-r--r--usr/include/zconf.h332
-rw-r--r--usr/include/zlib.h1357
-rw-r--r--usr/kinit/.gitignore3
-rw-r--r--usr/kinit/Kbuild43
-rw-r--r--usr/kinit/README9
-rw-r--r--usr/kinit/capabilities.c231
-rw-r--r--usr/kinit/capabilities.h10
-rw-r--r--usr/kinit/devname.c116
-rw-r--r--usr/kinit/do_mounts.c533
-rw-r--r--usr/kinit/do_mounts.h49
-rw-r--r--usr/kinit/do_mounts_md.c400
-rw-r--r--usr/kinit/do_mounts_mtd.c42
-rw-r--r--usr/kinit/fstype/Kbuild29
-rw-r--r--usr/kinit/fstype/btrfs.h57
-rw-r--r--usr/kinit/fstype/cramfs_fs.h85
-rw-r--r--usr/kinit/fstype/ext2_fs.h84
-rw-r--r--usr/kinit/fstype/ext3_fs.h134
-rw-r--r--usr/kinit/fstype/fstype.c445
-rw-r--r--usr/kinit/fstype/fstype.h20
-rw-r--r--usr/kinit/fstype/gfs2_fs.h56
-rw-r--r--usr/kinit/fstype/iso9660_sb.h24
-rw-r--r--usr/kinit/fstype/jfs_superblock.h114
-rw-r--r--usr/kinit/fstype/luks_fs.h44
-rw-r--r--usr/kinit/fstype/lvm2_sb.h18
-rw-r--r--usr/kinit/fstype/main.c57
-rw-r--r--usr/kinit/fstype/minix_fs.h85
-rw-r--r--usr/kinit/fstype/nilfs_fs.h64
-rw-r--r--usr/kinit/fstype/ocfs2_fs.h90
-rw-r--r--usr/kinit/fstype/reiser4_fs.h31
-rw-r--r--usr/kinit/fstype/reiserfs_fs.h74
-rw-r--r--usr/kinit/fstype/romfs_fs.h56
-rw-r--r--usr/kinit/fstype/squashfs_fs.h48
-rw-r--r--usr/kinit/fstype/swap_fs.h25
-rw-r--r--usr/kinit/fstype/xfs_sb.h21
-rw-r--r--usr/kinit/getarg.c57
-rw-r--r--usr/kinit/getintfile.c30
-rw-r--r--usr/kinit/initrd.c204
-rw-r--r--usr/kinit/ipconfig/Kbuild35
-rw-r--r--usr/kinit/ipconfig/README.ipconfig120
-rw-r--r--usr/kinit/ipconfig/bootp_packet.h44
-rw-r--r--usr/kinit/ipconfig/bootp_proto.c565
-rw-r--r--usr/kinit/ipconfig/bootp_proto.h10
-rw-r--r--usr/kinit/ipconfig/dhcp_proto.c301
-rw-r--r--usr/kinit/ipconfig/dhcp_proto.h19
-rw-r--r--usr/kinit/ipconfig/ipconfig.h25
-rw-r--r--usr/kinit/ipconfig/main.c924
-rw-r--r--usr/kinit/ipconfig/netdev.c279
-rw-r--r--usr/kinit/ipconfig/netdev.h107
-rw-r--r--usr/kinit/ipconfig/packet.c278
-rw-r--r--usr/kinit/ipconfig/packet.h12
-rw-r--r--usr/kinit/kinit.c331
-rw-r--r--usr/kinit/kinit.h70
-rw-r--r--usr/kinit/name_to_dev.c276
-rw-r--r--usr/kinit/nfsmount/Kbuild31
-rw-r--r--usr/kinit/nfsmount/README.locking26
-rw-r--r--usr/kinit/nfsmount/dummypmap.c281
-rw-r--r--usr/kinit/nfsmount/dummypmap.h11
-rw-r--r--usr/kinit/nfsmount/dummypmap_test.c2
-rw-r--r--usr/kinit/nfsmount/main.c288
-rw-r--r--usr/kinit/nfsmount/mount.c347
-rw-r--r--usr/kinit/nfsmount/nfsmount.h34
-rw-r--r--usr/kinit/nfsmount/portmap.c73
-rw-r--r--usr/kinit/nfsmount/sunrpc.c252
-rw-r--r--usr/kinit/nfsmount/sunrpc.h110
-rw-r--r--usr/kinit/nfsroot.c111
-rw-r--r--usr/kinit/ramdisk_load.c281
-rw-r--r--usr/kinit/readfile.c86
-rw-r--r--usr/kinit/resume/Kbuild34
-rw-r--r--usr/kinit/resume/resume.c25
-rw-r--r--usr/kinit/resume/resume.h7
-rw-r--r--usr/kinit/resume/resumelib.c106
-rw-r--r--usr/kinit/run-init/Kbuild38
-rw-r--r--usr/kinit/run-init/run-init.c114
-rw-r--r--usr/kinit/run-init/run-init.h38
-rw-r--r--usr/kinit/run-init/runinitlib.c232
-rw-r--r--usr/kinit/xpio.c51
-rw-r--r--usr/kinit/xpio.h11
-rw-r--r--usr/klibc/.gitignore12
-rw-r--r--usr/klibc/CAVEATS49
-rw-r--r--usr/klibc/Kbuild219
-rw-r--r--usr/klibc/LICENSE73
-rw-r--r--usr/klibc/README.klibc147
-rw-r--r--usr/klibc/SOCKETCALLS.def22
-rw-r--r--usr/klibc/SYSCALLS.def264
-rw-r--r--usr/klibc/__put_env.c74
-rw-r--r--usr/klibc/__shared_init.c2
-rw-r--r--usr/klibc/__signal.c20
-rw-r--r--usr/klibc/__static_init.c2
-rw-r--r--usr/klibc/abort.c18
-rw-r--r--usr/klibc/accept.c16
-rw-r--r--usr/klibc/access.c12
-rw-r--r--usr/klibc/alarm.c25
-rw-r--r--usr/klibc/alphasort.c12
-rw-r--r--usr/klibc/arch/README.klibc.arch81
-rw-r--r--usr/klibc/arch/alpha/Kbuild53
-rw-r--r--usr/klibc/arch/alpha/MCONFIG19
-rw-r--r--usr/klibc/arch/alpha/README-gcc22
-rw-r--r--usr/klibc/arch/alpha/crt0.S22
-rw-r--r--usr/klibc/arch/alpha/divide.c59
-rw-r--r--usr/klibc/arch/alpha/pipe.S38
-rw-r--r--usr/klibc/arch/alpha/setjmp.S75
-rw-r--r--usr/klibc/arch/alpha/sigaction.c16
-rw-r--r--usr/klibc/arch/alpha/sigreturn.S18
-rw-r--r--usr/klibc/arch/alpha/syscall.S26
-rw-r--r--usr/klibc/arch/alpha/sysdual.S33
-rw-r--r--usr/klibc/arch/alpha/sysstub.ph37
-rw-r--r--usr/klibc/arch/arm/Kbuild13
-rw-r--r--usr/klibc/arch/arm/MCONFIG40
-rw-r--r--usr/klibc/arch/arm/__muldi3.c15
-rw-r--r--usr/klibc/arch/arm/aeabi_nonsense.S9
-rw-r--r--usr/klibc/arch/arm/crt0.S23
-rw-r--r--usr/klibc/arch/arm/setjmp.S108
-rw-r--r--usr/klibc/arch/arm/syscall.S65
-rw-r--r--usr/klibc/arch/arm/sysstub.ph58
-rw-r--r--usr/klibc/arch/arm/vfork.S61
-rw-r--r--usr/klibc/arch/arm64/Kbuild7
-rw-r--r--usr/klibc/arch/arm64/MCONFIG27
-rw-r--r--usr/klibc/arch/arm64/crt0.S19
-rw-r--r--usr/klibc/arch/arm64/setjmp.S45
-rw-r--r--usr/klibc/arch/arm64/syscall.S25
-rw-r--r--usr/klibc/arch/arm64/sysstub.ph24
-rw-r--r--usr/klibc/arch/arm64/vfork.S33
-rw-r--r--usr/klibc/arch/i386/Kbuild17
-rw-r--r--usr/klibc/arch/i386/MCONFIG36
-rw-r--r--usr/klibc/arch/i386/crt0.S31
-rw-r--r--usr/klibc/arch/i386/libgcc/__ashldi3.S29
-rw-r--r--usr/klibc/arch/i386/libgcc/__ashrdi3.S29
-rw-r--r--usr/klibc/arch/i386/libgcc/__lshrdi3.S29
-rw-r--r--usr/klibc/arch/i386/libgcc/__muldi3.S34
-rw-r--r--usr/klibc/arch/i386/libgcc/__negdi2.S21
-rw-r--r--usr/klibc/arch/i386/open.S29
-rw-r--r--usr/klibc/arch/i386/openat.S26
-rw-r--r--usr/klibc/arch/i386/setjmp.S58
-rw-r--r--usr/klibc/arch/i386/syscall.S82
-rw-r--r--usr/klibc/arch/i386/sysstub.ph26
-rw-r--r--usr/klibc/arch/i386/varsyscall.S37
-rw-r--r--usr/klibc/arch/i386/vfork.S29
-rw-r--r--usr/klibc/arch/ia64/Kbuild13
-rw-r--r--usr/klibc/arch/ia64/MCONFIG17
-rw-r--r--usr/klibc/arch/ia64/crt0.S23
-rw-r--r--usr/klibc/arch/ia64/klibc.ld267
-rw-r--r--usr/klibc/arch/ia64/pipe.S27
-rw-r--r--usr/klibc/arch/ia64/setjmp.S343
-rw-r--r--usr/klibc/arch/ia64/sigaction.c64
-rw-r--r--usr/klibc/arch/ia64/syscall.S18
-rw-r--r--usr/klibc/arch/ia64/sysstub.ph29
-rw-r--r--usr/klibc/arch/ia64/vfork.S37
-rw-r--r--usr/klibc/arch/loongarch64/Kbuild7
-rw-r--r--usr/klibc/arch/loongarch64/MCONFIG23
-rw-r--r--usr/klibc/arch/loongarch64/crt0.S18
-rw-r--r--usr/klibc/arch/loongarch64/setjmp.S50
-rw-r--r--usr/klibc/arch/loongarch64/syscall.S13
-rw-r--r--usr/klibc/arch/loongarch64/sysstub.ph26
-rw-r--r--usr/klibc/arch/m68k/Kbuild9
-rw-r--r--usr/klibc/arch/m68k/MCONFIG23
-rw-r--r--usr/klibc/arch/m68k/crt0.S27
-rw-r--r--usr/klibc/arch/m68k/open.S22
-rw-r--r--usr/klibc/arch/m68k/openat.S26
-rw-r--r--usr/klibc/arch/m68k/setjmp.S43
-rw-r--r--usr/klibc/arch/m68k/syscall.S53
-rw-r--r--usr/klibc/arch/m68k/sysstub.ph26
-rw-r--r--usr/klibc/arch/m68k/vfork.S23
-rw-r--r--usr/klibc/arch/mips/Kbuild14
-rw-r--r--usr/klibc/arch/mips/MCONFIG21
-rw-r--r--usr/klibc/arch/mips/crt0.S22
-rw-r--r--usr/klibc/arch/mips/pipe.S15
-rw-r--r--usr/klibc/arch/mips/setjmp.S50
-rw-r--r--usr/klibc/arch/mips/syscall.S11
-rw-r--r--usr/klibc/arch/mips/sysstub.ph27
-rw-r--r--usr/klibc/arch/mips/vfork.S14
-rw-r--r--usr/klibc/arch/mips64/Kbuild14
-rw-r--r--usr/klibc/arch/mips64/MCONFIG34
-rw-r--r--usr/klibc/arch/mips64/crt0.S21
-rw-r--r--usr/klibc/arch/mips64/setjmp.S50
-rw-r--r--usr/klibc/arch/mips64/sysstub.ph27
-rw-r--r--usr/klibc/arch/parisc/Kbuild8
-rw-r--r--usr/klibc/arch/parisc/MCONFIG15
-rw-r--r--usr/klibc/arch/parisc/crt0.S37
-rw-r--r--usr/klibc/arch/parisc/setjmp.S88
-rw-r--r--usr/klibc/arch/parisc/syscall.S36
-rw-r--r--usr/klibc/arch/parisc/sysstub.ph28
-rw-r--r--usr/klibc/arch/parisc/vfork.S32
-rw-r--r--usr/klibc/arch/ppc/Kbuild12
-rw-r--r--usr/klibc/arch/ppc/MCONFIG29
-rw-r--r--usr/klibc/arch/ppc/crt0.S23
-rw-r--r--usr/klibc/arch/ppc/setjmp.S34
-rw-r--r--usr/klibc/arch/ppc/syscall.S16
-rw-r--r--usr/klibc/arch/ppc/sysstub.ph25
-rw-r--r--usr/klibc/arch/ppc64/Kbuild8
-rw-r--r--usr/klibc/arch/ppc64/MCONFIG27
-rw-r--r--usr/klibc/arch/ppc64/crt0.S43
-rw-r--r--usr/klibc/arch/ppc64/setjmp.S103
-rw-r--r--usr/klibc/arch/ppc64/syscall.c14
-rw-r--r--usr/klibc/arch/ppc64/sysstub.ph47
-rw-r--r--usr/klibc/arch/riscv64/Kbuild12
-rw-r--r--usr/klibc/arch/riscv64/MCONFIG29
-rw-r--r--usr/klibc/arch/riscv64/_main.S17
-rw-r--r--usr/klibc/arch/riscv64/crt0.S22
-rw-r--r--usr/klibc/arch/riscv64/setjmp.S50
-rw-r--r--usr/klibc/arch/riscv64/syscall.S13
-rw-r--r--usr/klibc/arch/riscv64/sysstub.ph26
-rw-r--r--usr/klibc/arch/s390/Kbuild22
-rw-r--r--usr/klibc/arch/s390/MCONFIG26
-rw-r--r--usr/klibc/arch/s390/crt0.S35
-rw-r--r--usr/klibc/arch/s390/mmap.c74
-rw-r--r--usr/klibc/arch/s390/setjmp.S74
-rw-r--r--usr/klibc/arch/s390/syscall.c16
-rw-r--r--usr/klibc/arch/s390/sysstub.ph63
-rw-r--r--usr/klibc/arch/sh/Kbuild8
-rw-r--r--usr/klibc/arch/sh/MCONFIG20
-rw-r--r--usr/klibc/arch/sh/crt0.S27
-rw-r--r--usr/klibc/arch/sh/pipe.S35
-rw-r--r--usr/klibc/arch/sh/setjmp.S64
-rw-r--r--usr/klibc/arch/sh/syscall.S35
-rw-r--r--usr/klibc/arch/sh/sysstub.ph38
-rw-r--r--usr/klibc/arch/sparc/Kbuild34
-rw-r--r--usr/klibc/arch/sparc/MCONFIG22
-rw-r--r--usr/klibc/arch/sparc/__muldi3.S27
-rw-r--r--usr/klibc/arch/sparc/crt0.S2
-rw-r--r--usr/klibc/arch/sparc/crt0i.S100
-rw-r--r--usr/klibc/arch/sparc/divrem.m4276
-rw-r--r--usr/klibc/arch/sparc/pipe.S31
-rw-r--r--usr/klibc/arch/sparc/setjmp.S38
-rw-r--r--usr/klibc/arch/sparc/sigaction.c21
-rw-r--r--usr/klibc/arch/sparc/smul.S160
-rw-r--r--usr/klibc/arch/sparc/syscall.S21
-rw-r--r--usr/klibc/arch/sparc/sysfork.S27
-rw-r--r--usr/klibc/arch/sparc/sysstub.ph25
-rw-r--r--usr/klibc/arch/sparc/umul.S193
-rw-r--r--usr/klibc/arch/sparc64/Kbuild8
-rw-r--r--usr/klibc/arch/sparc64/MCONFIG24
-rw-r--r--usr/klibc/arch/sparc64/crt0.S2
-rw-r--r--usr/klibc/arch/sparc64/pipe.S31
-rw-r--r--usr/klibc/arch/sparc64/setjmp.S55
-rw-r--r--usr/klibc/arch/sparc64/sigaction.c21
-rw-r--r--usr/klibc/arch/sparc64/syscall.S20
-rw-r--r--usr/klibc/arch/sparc64/sysfork.S28
-rw-r--r--usr/klibc/arch/sparc64/sysstub.ph25
-rw-r--r--usr/klibc/arch/x86_64/Kbuild8
-rw-r--r--usr/klibc/arch/x86_64/MCONFIG43
-rw-r--r--usr/klibc/arch/x86_64/crt0.S22
-rw-r--r--usr/klibc/arch/x86_64/setjmp.S54
-rw-r--r--usr/klibc/arch/x86_64/sigreturn.S15
-rw-r--r--usr/klibc/arch/x86_64/syscall.S28
-rw-r--r--usr/klibc/arch/x86_64/sysstub.ph23
-rw-r--r--usr/klibc/arch/x86_64/vfork.S26
-rw-r--r--usr/klibc/asprintf.c19
-rw-r--r--usr/klibc/assert.c14
-rw-r--r--usr/klibc/atexit.c10
-rw-r--r--usr/klibc/atexit.h18
-rw-r--r--usr/klibc/atoi.c3
-rw-r--r--usr/klibc/atol.c3
-rw-r--r--usr/klibc/atoll.c3
-rw-r--r--usr/klibc/atox.c14
-rw-r--r--usr/klibc/brk.c29
-rw-r--r--usr/klibc/bsd_signal.c14
-rw-r--r--usr/klibc/bsearch.c26
-rw-r--r--usr/klibc/bzero.c6
-rw-r--r--usr/klibc/calloc.c18
-rw-r--r--usr/klibc/chmod.c13
-rw-r--r--usr/klibc/chown.c12
-rw-r--r--usr/klibc/clearenv.c17
-rw-r--r--usr/klibc/clock_nanosleep.c17
-rw-r--r--usr/klibc/closelog.c18
-rw-r--r--usr/klibc/creat.c12
-rw-r--r--usr/klibc/ctype/ctypefunc.h13
-rw-r--r--usr/klibc/ctype/isalnum.c2
-rw-r--r--usr/klibc/ctype/isalpha.c2
-rw-r--r--usr/klibc/ctype/isascii.c2
-rw-r--r--usr/klibc/ctype/isblank.c2
-rw-r--r--usr/klibc/ctype/iscntrl.c2
-rw-r--r--usr/klibc/ctype/isdigit.c2
-rw-r--r--usr/klibc/ctype/isgraph.c2
-rw-r--r--usr/klibc/ctype/islower.c2
-rw-r--r--usr/klibc/ctype/isprint.c2
-rw-r--r--usr/klibc/ctype/ispunct.c2
-rw-r--r--usr/klibc/ctype/isspace.c2
-rw-r--r--usr/klibc/ctype/isupper.c2
-rw-r--r--usr/klibc/ctype/isxdigit.c2
-rw-r--r--usr/klibc/ctype/tolower.c2
-rw-r--r--usr/klibc/ctype/toupper.c2
-rw-r--r--usr/klibc/ctypes.c284
-rw-r--r--usr/klibc/daemon.c35
-rw-r--r--usr/klibc/dup2.c11
-rw-r--r--usr/klibc/endmntent.c9
-rw-r--r--usr/klibc/env.h10
-rw-r--r--usr/klibc/exec_l.c59
-rw-r--r--usr/klibc/execl.c8
-rw-r--r--usr/klibc/execle.c8
-rw-r--r--usr/klibc/execlp.c8
-rw-r--r--usr/klibc/execlpe.c8
-rw-r--r--usr/klibc/execv.c10
-rw-r--r--usr/klibc/execvp.c10
-rw-r--r--usr/klibc/execvpe.c75
-rw-r--r--usr/klibc/exit.c32
-rw-r--r--usr/klibc/fgets.c28
-rw-r--r--usr/klibc/fnmatch.c72
-rw-r--r--usr/klibc/fork.c21
-rw-r--r--usr/klibc/fprintf.c19
-rw-r--r--usr/klibc/fputc.c15
-rw-r--r--usr/klibc/fputs.c16
-rw-r--r--usr/klibc/fread2.c14
-rw-r--r--usr/klibc/fstat.c10
-rw-r--r--usr/klibc/fstatat.c36
-rw-r--r--usr/klibc/fstatfs.c19
-rw-r--r--usr/klibc/futimesat.c18
-rw-r--r--usr/klibc/fwrite2.c15
-rw-r--r--usr/klibc/getcwd.c15
-rw-r--r--usr/klibc/getdomainname.c25
-rw-r--r--usr/klibc/getenv.c24
-rw-r--r--usr/klibc/gethostname.c25
-rw-r--r--usr/klibc/getmntent.c61
-rw-r--r--usr/klibc/getopt.c97
-rw-r--r--usr/klibc/getopt_long.c152
-rw-r--r--usr/klibc/getpgrp.c10
-rw-r--r--usr/klibc/getpriority.c23
-rw-r--r--usr/klibc/gettimeofday.c22
-rw-r--r--usr/klibc/globals.c10
-rw-r--r--usr/klibc/inet/bindresvport.c46
-rw-r--r--usr/klibc/inet/inet_addr.c14
-rw-r--r--usr/klibc/inet/inet_aton.c22
-rw-r--r--usr/klibc/inet/inet_ntoa.c16
-rw-r--r--usr/klibc/inet/inet_ntop.c54
-rw-r--r--usr/klibc/inet/inet_pton.c78
-rw-r--r--usr/klibc/isatty.c16
-rw-r--r--usr/klibc/jrand48.c24
-rw-r--r--usr/klibc/lchown.c12
-rw-r--r--usr/klibc/libc_init.c121
-rw-r--r--usr/klibc/libgcc/__ashldi3.c23
-rw-r--r--usr/klibc/libgcc/__ashrdi3.c23
-rw-r--r--usr/klibc/libgcc/__clzsi2.c36
-rw-r--r--usr/klibc/libgcc/__divdi3.c29
-rw-r--r--usr/klibc/libgcc/__divsi3.c29
-rw-r--r--usr/klibc/libgcc/__lshrdi3.c23
-rw-r--r--usr/klibc/libgcc/__moddi3.c29
-rw-r--r--usr/klibc/libgcc/__modsi3.c29
-rw-r--r--usr/klibc/libgcc/__udivdi3.c13
-rw-r--r--usr/klibc/libgcc/__udivmoddi4.c32
-rw-r--r--usr/klibc/libgcc/__udivmodsi4.c32
-rw-r--r--usr/klibc/libgcc/__udivsi3.c13
-rw-r--r--usr/klibc/libgcc/__umoddi3.c16
-rw-r--r--usr/klibc/libgcc/__umodsi3.c16
-rw-r--r--usr/klibc/link.c12
-rw-r--r--usr/klibc/lrand48.c13
-rw-r--r--usr/klibc/lseek.c31
-rw-r--r--usr/klibc/lstat.c10
-rw-r--r--usr/klibc/makeerrlist.pl98
-rw-r--r--usr/klibc/malloc.c299
-rw-r--r--usr/klibc/malloc.h50
-rw-r--r--usr/klibc/memccpy.c23
-rw-r--r--usr/klibc/memchr.c19
-rw-r--r--usr/klibc/memcmp.c19
-rw-r--r--usr/klibc/memcpy.c29
-rw-r--r--usr/klibc/memmem.c55
-rw-r--r--usr/klibc/memmove.c36
-rw-r--r--usr/klibc/memrchr.c19
-rw-r--r--usr/klibc/memset.c30
-rw-r--r--usr/klibc/memswap.c24
-rw-r--r--usr/klibc/mkdir.c14
-rw-r--r--usr/klibc/mknod.c14
-rw-r--r--usr/klibc/mmap.c40
-rw-r--r--usr/klibc/mrand48.c13
-rw-r--r--usr/klibc/nanosleep.c8
-rw-r--r--usr/klibc/nice.c19
-rw-r--r--usr/klibc/nrand48.c11
-rw-r--r--usr/klibc/nullenv.c8
-rw-r--r--usr/klibc/onexit.c23
-rw-r--r--usr/klibc/open.c47
-rw-r--r--usr/klibc/openat.c22
-rw-r--r--usr/klibc/pause.c17
-rw-r--r--usr/klibc/perror.c13
-rw-r--r--usr/klibc/pipe.c11
-rw-r--r--usr/klibc/poll.c21
-rw-r--r--usr/klibc/ppoll.c19
-rw-r--r--usr/klibc/pread.c30
-rw-r--r--usr/klibc/printf.c19
-rw-r--r--usr/klibc/pselect.c22
-rw-r--r--usr/klibc/pty.c31
-rw-r--r--usr/klibc/putchar.c15
-rw-r--r--usr/klibc/putenv.c37
-rw-r--r--usr/klibc/puts.c13
-rw-r--r--usr/klibc/pwrite.c30
-rw-r--r--usr/klibc/qsort.c46
-rw-r--r--usr/klibc/raise.c11
-rw-r--r--usr/klibc/readdir.c68
-rw-r--r--usr/klibc/readlink.c12
-rw-r--r--usr/klibc/realloc.c48
-rw-r--r--usr/klibc/realpath.c49
-rw-r--r--usr/klibc/reboot.c15
-rw-r--r--usr/klibc/recv.c11
-rw-r--r--usr/klibc/remove.c18
-rw-r--r--usr/klibc/rename.c11
-rw-r--r--usr/klibc/renameat.c12
-rw-r--r--usr/klibc/rmdir.c12
-rw-r--r--usr/klibc/sbrk.c45
-rw-r--r--usr/klibc/scandir.c71
-rw-r--r--usr/klibc/seed48.c18
-rw-r--r--usr/klibc/select.c31
-rw-r--r--usr/klibc/send.c11
-rw-r--r--usr/klibc/setegid.c10
-rw-r--r--usr/klibc/setenv.c42
-rw-r--r--usr/klibc/seteuid.c10
-rw-r--r--usr/klibc/setmntent.c7
-rw-r--r--usr/klibc/setpgrp.c10
-rw-r--r--usr/klibc/settimeofday.c22
-rw-r--r--usr/klibc/sha1hash.c317
-rw-r--r--usr/klibc/shared-stub.S22
-rw-r--r--usr/klibc/shm_open.c23
-rw-r--r--usr/klibc/shm_unlink.c23
-rw-r--r--usr/klibc/sigabbrev.c121
-rw-r--r--usr/klibc/sigaction.c61
-rw-r--r--usr/klibc/siglist.c121
-rw-r--r--usr/klibc/siglongjmp.c16
-rw-r--r--usr/klibc/sigpending.c14
-rw-r--r--usr/klibc/sigprocmask.c14
-rw-r--r--usr/klibc/sigsuspend.c15
-rw-r--r--usr/klibc/sleep.c22
-rw-r--r--usr/klibc/snprintf.c16
-rw-r--r--usr/klibc/socketcalls.pl82
-rw-r--r--usr/klibc/socketcalls/.gitignore4
-rw-r--r--usr/klibc/socketcalls/Kbuild52
-rw-r--r--usr/klibc/socketcalls/socketcommon.h15
-rw-r--r--usr/klibc/sprintf.c18
-rw-r--r--usr/klibc/srand48.c15
-rw-r--r--usr/klibc/sscanf.c17
-rw-r--r--usr/klibc/stat.c10
-rw-r--r--usr/klibc/statfs.c19
-rw-r--r--usr/klibc/stdio/clearerr.c9
-rw-r--r--usr/klibc/stdio/fclose.c22
-rw-r--r--usr/klibc/stdio/fdopen.c57
-rw-r--r--usr/klibc/stdio/feof.c8
-rw-r--r--usr/klibc/stdio/ferror.c8
-rw-r--r--usr/klibc/stdio/fflush.c60
-rw-r--r--usr/klibc/stdio/fgetc.c19
-rw-r--r--usr/klibc/stdio/fileno.c8
-rw-r--r--usr/klibc/stdio/fopen.c59
-rw-r--r--usr/klibc/stdio/fread.c79
-rw-r--r--usr/klibc/stdio/fseek.c28
-rw-r--r--usr/klibc/stdio/ftell.c12
-rw-r--r--usr/klibc/stdio/fwrite.c97
-rw-r--r--usr/klibc/stdio/rewind.c8
-rw-r--r--usr/klibc/stdio/stdioint.h38
-rw-r--r--usr/klibc/stdio/ungetc.c17
-rw-r--r--usr/klibc/strcasecmp.c24
-rw-r--r--usr/klibc/strcat.c11
-rw-r--r--usr/klibc/strchr.c19
-rw-r--r--usr/klibc/strcmp.c21
-rw-r--r--usr/klibc/strcpy.c20
-rw-r--r--usr/klibc/strcspn.c12
-rw-r--r--usr/klibc/strdup.c17
-rw-r--r--usr/klibc/strerror.c33
-rw-r--r--usr/klibc/strlcat.c31
-rw-r--r--usr/klibc/strlcpy.c27
-rw-r--r--usr/klibc/strlen.c13
-rw-r--r--usr/klibc/strncasecmp.c24
-rw-r--r--usr/klibc/strncat.c22
-rw-r--r--usr/klibc/strncmp.c21
-rw-r--r--usr/klibc/strncpy.c24
-rw-r--r--usr/klibc/strndup.c18
-rw-r--r--usr/klibc/strnlen.c18
-rw-r--r--usr/klibc/strntoimax.c13
-rw-r--r--usr/klibc/strntoumax.c77
-rw-r--r--usr/klibc/strpbrk.c14
-rw-r--r--usr/klibc/strrchr.c23
-rw-r--r--usr/klibc/strsep.c21
-rw-r--r--usr/klibc/strsignal.c26
-rw-r--r--usr/klibc/strspn.c12
-rw-r--r--usr/klibc/strstr.c11
-rw-r--r--usr/klibc/strtoimax.c3
-rw-r--r--usr/klibc/strtok.c12
-rw-r--r--usr/klibc/strtok_r.c13
-rw-r--r--usr/klibc/strtol.c3
-rw-r--r--usr/klibc/strtoll.c3
-rw-r--r--usr/klibc/strtotimespec.c5
-rw-r--r--usr/klibc/strtotimeval.c5
-rw-r--r--usr/klibc/strtotimex.c40
-rw-r--r--usr/klibc/strtoul.c3
-rw-r--r--usr/klibc/strtoull.c3
-rw-r--r--usr/klibc/strtoumax.c3
-rw-r--r--usr/klibc/strtox.c14
-rw-r--r--usr/klibc/strxspn.c29
-rw-r--r--usr/klibc/strxspn.h12
-rw-r--r--usr/klibc/symlink.c12
-rw-r--r--usr/klibc/syscalls.pl286
-rw-r--r--usr/klibc/syscalls/.gitignore6
-rw-r--r--usr/klibc/syscalls/Kbuild99
-rw-r--r--usr/klibc/syscalls/syscommon.h34
-rw-r--r--usr/klibc/sysconf/sysconf.c8
-rw-r--r--usr/klibc/syslog.c89
-rw-r--r--usr/klibc/system.c60
-rw-r--r--usr/klibc/sysv_signal.c11
-rw-r--r--usr/klibc/tests/Kbuild69
-rw-r--r--usr/klibc/tests/environ.c23
-rw-r--r--usr/klibc/tests/fcntl.c51
-rw-r--r--usr/klibc/tests/fnmatch.c13
-rw-r--r--usr/klibc/tests/getoptlong.c57
-rw-r--r--usr/klibc/tests/getopttest.c32
-rw-r--r--usr/klibc/tests/getpagesize.c10
-rw-r--r--usr/klibc/tests/hello.c7
-rw-r--r--usr/klibc/tests/idtest.c14
-rw-r--r--usr/klibc/tests/lseek.c15
-rw-r--r--usr/klibc/tests/malloctest.c4146
-rw-r--r--usr/klibc/tests/malloctest2.c62
-rw-r--r--usr/klibc/tests/malloctest3.c57
-rw-r--r--usr/klibc/tests/memstrtest.c28
-rw-r--r--usr/klibc/tests/microhello.c9
-rw-r--r--usr/klibc/tests/minihello.c7
-rw-r--r--usr/klibc/tests/mmaptest.c73
-rw-r--r--usr/klibc/tests/opentest.c15
-rw-r--r--usr/klibc/tests/pipetest.c39
-rw-r--r--usr/klibc/tests/rtsig.c12
-rw-r--r--usr/klibc/tests/select.c55
-rw-r--r--usr/klibc/tests/setenvtest.c39
-rw-r--r--usr/klibc/tests/setjmptest.c37
-rw-r--r--usr/klibc/tests/sig-nodefer.c55
-rw-r--r--usr/klibc/tests/sigint.c64
-rw-r--r--usr/klibc/tests/socket.c18
-rw-r--r--usr/klibc/tests/sscanf.c36
-rw-r--r--usr/klibc/tests/stat.c62
-rw-r--r--usr/klibc/tests/statfs.c41
-rw-r--r--usr/klibc/tests/stdio.c70
-rw-r--r--usr/klibc/tests/strlcpycat.c111
-rw-r--r--usr/klibc/tests/strsearch.c113
-rw-r--r--usr/klibc/tests/strtoimax.c23
-rw-r--r--usr/klibc/tests/strtotime.c25
-rw-r--r--usr/klibc/tests/sysconf.c14
-rw-r--r--usr/klibc/tests/testrand48.c19
-rw-r--r--usr/klibc/tests/testvsnp.c118
-rw-r--r--usr/klibc/tests/vfork.c45
-rw-r--r--usr/klibc/time.c19
-rw-r--r--usr/klibc/umount.c12
-rw-r--r--usr/klibc/unlink.c12
-rw-r--r--usr/klibc/unsetenv.c44
-rw-r--r--usr/klibc/userdb/getgrgid.c18
-rw-r--r--usr/klibc/userdb/getgrnam.c18
-rw-r--r--usr/klibc/userdb/getpwnam.c19
-rw-r--r--usr/klibc/userdb/getpwuid.c19
-rw-r--r--usr/klibc/userdb/root_group.c12
-rw-r--r--usr/klibc/userdb/root_user.c17
-rw-r--r--usr/klibc/userdb/userdb.h19
-rw-r--r--usr/klibc/usleep.c17
-rw-r--r--usr/klibc/utime.c20
-rw-r--r--usr/klibc/utimes.c18
-rw-r--r--usr/klibc/vasprintf.c25
-rw-r--r--usr/klibc/version1
-rw-r--r--usr/klibc/vfork.c16
-rw-r--r--usr/klibc/vfprintf.c26
-rw-r--r--usr/klibc/vprintf.c11
-rw-r--r--usr/klibc/vsnprintf.c488
-rw-r--r--usr/klibc/vsprintf.c11
-rw-r--r--usr/klibc/vsscanf.c392
-rw-r--r--usr/klibc/wait.c12
-rw-r--r--usr/klibc/wait3.c12
-rw-r--r--usr/klibc/waitpid.c12
-rw-r--r--usr/klibc/zalloc.c17
-rw-r--r--usr/klibc/zlib/FAQ339
-rw-r--r--usr/klibc/zlib/INDEX51
-rw-r--r--usr/klibc/zlib/Kbuild12
-rw-r--r--usr/klibc/zlib/README125
-rw-r--r--usr/klibc/zlib/adler32.c149
-rw-r--r--usr/klibc/zlib/algorithm.txt209
-rw-r--r--usr/klibc/zlib/compress.c79
-rw-r--r--usr/klibc/zlib/crc32.c423
-rw-r--r--usr/klibc/zlib/crc32.h441
-rw-r--r--usr/klibc/zlib/deflate.c1736
-rw-r--r--usr/klibc/zlib/deflate.h331
-rw-r--r--usr/klibc/zlib/gzio.c1029
-rw-r--r--usr/klibc/zlib/infback.c623
-rw-r--r--usr/klibc/zlib/inffast.c318
-rw-r--r--usr/klibc/zlib/inffast.h11
-rw-r--r--usr/klibc/zlib/inffixed.h94
-rw-r--r--usr/klibc/zlib/inflate.c1368
-rw-r--r--usr/klibc/zlib/inflate.h115
-rw-r--r--usr/klibc/zlib/inftrees.c329
-rw-r--r--usr/klibc/zlib/inftrees.h55
-rw-r--r--usr/klibc/zlib/trees.c1219
-rw-r--r--usr/klibc/zlib/trees.h127
-rw-r--r--usr/klibc/zlib/uncompr.c61
-rw-r--r--usr/klibc/zlib/zconf.in.h332
-rw-r--r--usr/klibc/zlib/zlib.3159
-rw-r--r--usr/klibc/zlib/zutil.c318
-rw-r--r--usr/klibc/zlib/zutil.h269
-rw-r--r--usr/utils/Kbuild86
-rw-r--r--usr/utils/cat.c309
-rw-r--r--usr/utils/chroot.c30
-rw-r--r--usr/utils/cpio.c1079
-rw-r--r--usr/utils/dd.c540
-rw-r--r--usr/utils/dmesg.c79
-rw-r--r--usr/utils/false.c4
-rw-r--r--usr/utils/file_mode.c143
-rw-r--r--usr/utils/file_mode.h6
-rw-r--r--usr/utils/halt.c64
-rw-r--r--usr/utils/insmod.c140
-rw-r--r--usr/utils/kill.c33
-rw-r--r--usr/utils/ln.c77
-rw-r--r--usr/utils/losetup.c400
-rw-r--r--usr/utils/ls.c223
-rw-r--r--usr/utils/minips.c511
-rw-r--r--usr/utils/mkdir.c154
-rw-r--r--usr/utils/mkfifo.c70
-rw-r--r--usr/utils/mknod.c84
-rw-r--r--usr/utils/mount_main.c156
-rw-r--r--usr/utils/mount_opts.c102
-rw-r--r--usr/utils/mount_opts.h26
-rw-r--r--usr/utils/mv.c69
-rw-r--r--usr/utils/nuke.c121
-rw-r--r--usr/utils/pivot_root.c19
-rw-r--r--usr/utils/readlink.c57
-rw-r--r--usr/utils/sleep.c26
-rw-r--r--usr/utils/sync.c7
-rw-r--r--usr/utils/true.c4
-rw-r--r--usr/utils/umount.c51
-rw-r--r--usr/utils/uname.c155
887 files changed, 83477 insertions, 0 deletions
diff --git a/usr/.gitignore b/usr/.gitignore
new file mode 100644
index 0000000..77534ee
--- /dev/null
+++ b/usr/.gitignore
@@ -0,0 +1,2 @@
+# Generated headers (we don't want a .gitignore in the include directory!)
+/include/klibc/havesyscall.h
diff --git a/usr/Kbuild b/usr/Kbuild
new file mode 100644
index 0000000..890811c
--- /dev/null
+++ b/usr/Kbuild
@@ -0,0 +1,75 @@
+#
+# kbuild file for usr/ - including initramfs image and klibc
+#
+
+CONFIG_KLIBC := 1
+
+include-subdir := include
+klibc-subdir := klibc
+usr-subdirs := kinit utils dash gzip
+subdir- := $(include-subdir) $(klibc-subdir) $(usr-subdirs)
+
+usr-subdirs := $(addprefix _usr_,$(usr-subdirs))
+klibc-subdir := $(addprefix _usr_,$(klibc-subdir))
+
+# klibc binaries
+ifdef CONFIG_KLIBC
+
+# .initramfs_data.cpio.gz.d is used to identify all files included
+# in initramfs and to detect if any files are added/removed.
+# Removed files are identified by directory timestamp being updated
+# The dependency list is generated by gen_initramfs.sh -l
+ifneq ($(wildcard $(obj)/.initramfs_data.cpio.gz.d),)
+ include $(obj)/.initramfs_data.cpio.gz.d
+endif
+
+# build klibc library before the klibc programs
+# build klibc programs before cpio.gz
+.PHONY: initramfs $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+initramfs: $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+$(deps_initramfs): $(usr-subdirs) $(klibc-subdir) $(include-subdir)
+
+$(usr-subdirs): $(klibc-subdir)
+ $(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+
+$(klibc-subdir): $(include-subdir)
+ $(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+
+$(include-subdir):
+ $(Q)$(MAKE) $(klibc)=$(src)/$(patsubst _usr_%,%,$(@))
+endif
+
+
+# Generate builtin.o based on initramfs_data.o
+obj-y := initramfs_data.o
+
+# initramfs_data.o contains the initramfs_data.cpio.gz image.
+# The image is included using .incbin, a dependency which is not
+# tracked automatically.
+$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE
+
+#####
+# Generate the initramfs cpio archive
+
+hostprogs-y := gen_init_cpio
+ginitramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh
+ramfs-def := $(srctree)/$(src)/initramfs.default
+ramfs-input := $(shell echo $(CONFIG_INITRAMFS_SOURCE))
+ramfs-input := $(if $(ramfs-input), $(ramfs-input), $(ramfs-def))
+
+ramfs-args := \
+ $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
+ $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
+
+quiet_cmd_initfs = GEN $@
+ cmd_initfs = $(ginitramfs) -o $@ $(ramfs-args) $(ramfs-input)
+
+targets := initramfs_data.cpio.gz
+# We rebuild initramfs_data.cpio.gz if:
+# 1) Any included file is newer then initramfs_data.cpio.gz
+# 2) There are changes in which files are included (added or deleted)
+# 3) If gen_init_cpio are newer than initramfs_data.cpio.gz
+# 4) arguments to gen_initramfs.sh changes
+$(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) initramfs
+ $(Q)$(ginitramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d
+ $(call if_changed,initfs)
diff --git a/usr/dash/.gitignore b/usr/dash/.gitignore
new file mode 100644
index 0000000..480952f
--- /dev/null
+++ b/usr/dash/.gitignore
@@ -0,0 +1,13 @@
+arith.[ch]
+.builtins.def.d
+builtins.[ch]
+builtins.def
+init.c
+mkinit
+mknodes
+mksyntax
+nodes.[ch]
+sh
+sh.shared
+syntax.[ch]
+token.h
diff --git a/usr/dash/Kbuild b/usr/dash/Kbuild
new file mode 100644
index 0000000..c0f8dcb
--- /dev/null
+++ b/usr/dash/Kbuild
@@ -0,0 +1,103 @@
+#
+# Kbuild file for dash
+#
+
+config-cppflags := -DBSD=1 -DSMALL -DJOBS=0 -DHAVE_CONFIG_H -DSHELL
+config-cppflags += -DGLOB_BROKEN -DIFS_BROKEN
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src) -I$(objtree)/$(obj)
+EXTRA_KLIBCCFLAGS += -include $(srctree)/$(src)/config.h
+EXTRA_KLIBCCFLAGS += $(config-cppflags)
+
+HOST_EXTRACFLAGS := $(config-cppflags)
+
+init-o-files := alias.o arith_yacc.o arith_yylex.o cd.o error.o eval.o exec.o expand.o \
+ histedit.o input.o jobs.o mail.o main.o memalloc.o miscbltin.o \
+ mystring.o options.o parser.o redir.o show.o trap.o output.o \
+ bltin/printf.o system.o bltin/test.o var.o
+
+gen-o-files := builtins.o init.o nodes.o syntax.o
+
+static/sh-y := $(init-o-files) $(gen-o-files)
+
+hostprogs-y := mkinit mksyntax mknodes mksignames
+gen-h-files := builtins.h nodes.h syntax.h token.h
+
+static-y := static/sh
+
+# The shared binary
+shared-y := shared/sh
+shared/sh-y := $(static/sh-y)
+
+# For cleaning
+targets := static/sh static/sh.g shared/sh shared/sh.g $(gen-o-files)
+
+# explicit dependency for all generated files
+$(addprefix $(obj)/, $(static/sh-y)): $(addprefix $(obj)/, $(gen-h-files))
+
+# Generate token.h
+targets += token.h
+quiet_cmd_mktokens = GEN $@
+ cmd_mktokens = sh $< > $@
+$(obj)/token.h: $(src)/mktokens
+ $(call if_changed,mktokens)
+
+# Generate builtins.def
+targets += builtins.def
+quiet_cmd_mkbuiltins_def = GEN $@
+ cmd_mkbuiltins_def = $(HOSTCC) $(hostc_flags) -x c -E -o $@ $<
+$(obj)/builtins.def: $(src)/builtins.def.in $(src)/config.h
+ $(call if_changed,mkbuiltins_def)
+
+# Generate builtins{.c + .h}
+targets += builtins.c builtins.h
+quiet_cmd_mkbuiltins = GEN $@
+ cmd_mkbuiltins = mkdir -p $(obj)/bltin && cd $(obj) && \
+ sh $(srctree)/$(src)/mkbuiltins builtins.def
+$(obj)/builtins.c: $(src)/mkbuiltins $(obj)/builtins.def
+ $(call cmd,mkbuiltins)
+
+# side effect..
+$(obj)/builtins.h: $(obj)/builtins.c
+ $(Q):
+
+# Generate init.c
+targets += init.c
+init-c-files := $(addprefix $(srctree)/$(src)/, $(init-o-files:.o=.c))
+quiet_cmd_mkinit = GEN $@
+ cmd_mkinit = cd $(obj) && ./mkinit $(init-c-files)
+$(obj)/init.c: $(obj)/mkinit $(init-c-files)
+ $(call cmd,mkinit)
+
+# Generate nodes{.c + .h}
+targets += nodes.c nodes.h
+quiet_cmd_mknodes = GEN $@
+ cmd_mknodes = cd $(obj) && ./mknodes $(srctree)/$(src)/nodetypes \
+ $(srctree)/$(src)/nodes.c.pat
+$(obj)/nodes.c: $(obj)/mknodes $(src)/nodetypes $(src)/nodes.c.pat
+ $(call cmd,mknodes)
+
+# side effect..
+$(obj)/nodes.h: $(obj)/nodes.c
+ $(Q):
+
+# Generate syntax{.c + .h}
+targets += syntax.c syntax.h
+quiet_cmd_mksyntax = GEN $@
+ cmd_mksyntax = cd $(obj) && ./mksyntax
+$(obj)/syntax.c: $(obj)/mksyntax
+ $(call cmd,mksyntax)
+
+# side effect..
+$(obj)/syntax.h: $(obj)/syntax.c
+ $(Q):
+
+# Clean deletes the static and shared dir
+clean-dirs := static shared
+
+# Targets to install
+ifdef KLIBCSHAREDFLAGS
+install-y := shared/sh
+else
+install-y := static/sh
+endif
diff --git a/usr/dash/README.dash b/usr/dash/README.dash
new file mode 100644
index 0000000..d67a5af
--- /dev/null
+++ b/usr/dash/README.dash
@@ -0,0 +1,50 @@
+This version of dash was obtained from
+
+git://git.kernel.org/pub/scm/utils/dash/dash.git
+
+It corresponds up to changeset 46abc8c6d8a5e9a5712bdc1312c0b6960eec65a4
+omitting ee5cbe9fd6bc02f31b4d955606288de36c3d4eab.
+
+Several changes have been made for klibc:
+
+* The build system is changed from autotools to kbuild, with a static config.h
+* Use of strtod() is guarded by HAVE_STRTOD, which we don't define
+* The built-in times command, which requires floating-point support, is
+ disabled
+* The signal_names[] array is replaced by a signal_name() function using
+ klibc's own signal name array. decode_signal() is changed similarly.
+* The read built-in implements the -t option like bash
+* mktokens is modified to support out-of-tree builds
+* mkbuiltins is modified to sort with LC_ALL=C
+* Some header files have header guards added
+* Changelog and some manual pages are omitted
+* Automatic whitespace fixups
+
+HOWTO sync branch:
+
+1) Generate mailbox of patches and fix up their paths:
+
+ git format-patch --subject-prefix='' -N --stdout <changeset>.. \
+ | awk '(FNR == 1 || blank) && /^From / { header = 1; hash = $2 }
+ header && /^Subject:/ { sub("^Subject:", "Subject: [klibc] dash:") }
+ { print; blank = /^$/ }
+ header && blank {
+ print "[ dash commit", hash, "]"; print
+ header = 0
+ }' \
+ | filterdiff --strip 2 --addoldprefix a/usr/dash/ --addnewprefix b/usr/dash/ \
+ --exclude="*/configure.ac" --exclude="*/ChangeLog" \
+ --exclude="*/dash.1" --exclude="*/Makefile.am" \
+ --exclude="*/mksignames.c" \
+ > dash.mbox
+
+2) Import patches from mailbox:
+
+ git am --whitespace=fix -k -i -s ../dash/dash.mbox
+
+3) update config.h
+
+Generate klibc config.h in dash repository:
+ automake --add-missing
+ autoreconf
+ ./configure CC=klcc
diff --git a/usr/dash/TOUR b/usr/dash/TOUR
new file mode 100644
index 0000000..056e79b
--- /dev/null
+++ b/usr/dash/TOUR
@@ -0,0 +1,343 @@
+# @(#)TOUR 8.1 (Berkeley) 5/31/93
+
+NOTE -- This is the original TOUR paper distributed with ash and
+does not represent the current state of the shell. It is provided anyway
+since it provides helpful information for how the shell is structured,
+but be warned that things have changed -- the current shell is
+still under development.
+
+================================================================
+
+ A Tour through Ash
+
+ Copyright 1989 by Kenneth Almquist.
+
+
+DIRECTORIES: The subdirectory bltin contains commands which can
+be compiled stand-alone. The rest of the source is in the main
+ash directory.
+
+SOURCE CODE GENERATORS: Files whose names begin with "mk" are
+programs that generate source code. A complete list of these
+programs is:
+
+ program intput files generates
+ ------- ------------ ---------
+ mkbuiltins builtins builtins.h builtins.c
+ mkinit *.c init.c
+ mknodes nodetypes nodes.h nodes.c
+ mksignames - signames.h signames.c
+ mksyntax - syntax.h syntax.c
+ mktokens - token.h
+ bltin/mkexpr unary_op binary_op operators.h operators.c
+
+There are undoubtedly too many of these. Mkinit searches all the
+C source files for entries looking like:
+
+ INIT {
+ x = 1; /* executed during initialization */
+ }
+
+ RESET {
+ x = 2; /* executed when the shell does a longjmp
+ back to the main command loop */
+ }
+
+It pulls this code out into routines which are when particular
+events occur. The intent is to improve modularity by isolating
+the information about which modules need to be explicitly
+initialized/reset within the modules themselves.
+
+Mkinit recognizes several constructs for placing declarations in
+the init.c file.
+ INCLUDE "file.h"
+includes a file. The storage class MKINIT makes a declaration
+available in the init.c file, for example:
+ MKINIT int funcnest; /* depth of function calls */
+MKINIT alone on a line introduces a structure or union declara-
+tion:
+ MKINIT
+ struct redirtab {
+ short renamed[10];
+ };
+Preprocessor #define statements are copied to init.c without any
+special action to request this.
+
+INDENTATION: The ash source is indented in multiples of six
+spaces. The only study that I have heard of on the subject con-
+cluded that the optimal amount to indent is in the range of four
+to six spaces. I use six spaces since it is not too big a jump
+from the widely used eight spaces. If you really hate six space
+indentation, use the adjind (source included) program to change
+it to something else.
+
+EXCEPTIONS: Code for dealing with exceptions appears in
+exceptions.c. The C language doesn't include exception handling,
+so I implement it using setjmp and longjmp. The global variable
+exception contains the type of exception. EXERROR is raised by
+calling error. EXINT is an interrupt.
+
+INTERRUPTS: In an interactive shell, an interrupt will cause an
+EXINT exception to return to the main command loop. (Exception:
+EXINT is not raised if the user traps interrupts using the trap
+command.) The INTOFF and INTON macros (defined in exception.h)
+provide uninterruptable critical sections. Between the execution
+of INTOFF and the execution of INTON, interrupt signals will be
+held for later delivery. INTOFF and INTON can be nested.
+
+MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
+which call error when there is no memory left. It also defines a
+stack oriented memory allocation scheme. Allocating off a stack
+is probably more efficient than allocation using malloc, but the
+big advantage is that when an exception occurs all we have to do
+to free up the memory in use at the time of the exception is to
+restore the stack pointer. The stack is implemented using a
+linked list of blocks.
+
+STPUTC: If the stack were contiguous, it would be easy to store
+strings on the stack without knowing in advance how long the
+string was going to be:
+ p = stackptr;
+ *p++ = c; /* repeated as many times as needed */
+ stackptr = p;
+The folloing three macros (defined in memalloc.h) perform these
+operations, but grow the stack if you run off the end:
+ STARTSTACKSTR(p);
+ STPUTC(c, p); /* repeated as many times as needed */
+ grabstackstr(p);
+
+We now start a top-down look at the code:
+
+MAIN.C: The main routine performs some initialization, executes
+the user's profile if necessary, and calls cmdloop. Cmdloop is
+repeatedly parses and executes commands.
+
+OPTIONS.C: This file contains the option processing code. It is
+called from main to parse the shell arguments when the shell is
+invoked, and it also contains the set builtin. The -i and -j op-
+tions (the latter turns on job control) require changes in signal
+handling. The routines setjobctl (in jobs.c) and setinteractive
+(in trap.c) are called to handle changes to these options.
+
+PARSING: The parser code is all in parser.c. A recursive des-
+cent parser is used. Syntax tables (generated by mksyntax) are
+used to classify characters during lexical analysis. There are
+three tables: one for normal use, one for use when inside single
+quotes, and one for use when inside double quotes. The tables
+are machine dependent because they are indexed by character vari-
+ables and the range of a char varies from machine to machine.
+
+PARSE OUTPUT: The output of the parser consists of a tree of
+nodes. The various types of nodes are defined in the file node-
+types.
+
+Nodes of type NARG are used to represent both words and the con-
+tents of here documents. An early version of ash kept the con-
+tents of here documents in temporary files, but keeping here do-
+cuments in memory typically results in significantly better per-
+formance. It would have been nice to make it an option to use
+temporary files for here documents, for the benefit of small
+machines, but the code to keep track of when to delete the tem-
+porary files was complex and I never fixed all the bugs in it.
+(AT&T has been maintaining the Bourne shell for more than ten
+years, and to the best of my knowledge they still haven't gotten
+it to handle temporary files correctly in obscure cases.)
+
+The text field of a NARG structure points to the text of the
+word. The text consists of ordinary characters and a number of
+special codes defined in parser.h. The special codes are:
+
+ CTLVAR Variable substitution
+ CTLENDVAR End of variable substitution
+ CTLBACKQ Command substitution
+ CTLESC Escape next character
+
+A variable substitution contains the following elements:
+
+ CTLVAR type name '=' [ alternative-text CTLENDVAR ]
+
+The type field is a single character specifying the type of sub-
+stitution. The possible types are:
+
+ VSNORMAL $var
+ VSMINUS ${var-text}
+ VSMINUS|VSNUL ${var:-text}
+ VSPLUS ${var+text}
+ VSPLUS|VSNUL ${var:+text}
+ VSQUESTION ${var?text}
+ VSQUESTION|VSNUL ${var:?text}
+ VSASSIGN ${var=text}
+ VSASSIGN|VSNUL ${var=text}
+
+The name of the variable comes next, terminated by an equals
+sign. If the type is not VSNORMAL, then the text field in the
+substitution follows, terminated by a CTLENDVAR byte.
+
+Commands in back quotes are parsed and stored in a linked list.
+The locations of these commands in the string are indicated by
+the CTLBACKQ character.
+
+The character CTLESC escapes the next character, so that in case
+any of the CTL characters mentioned above appear in the input,
+they can be passed through transparently. CTLESC is also used to
+escape '*', '?', '[', and '!' characters which were quoted by the
+user and thus should not be used for file name generation.
+
+CTLESC characters have proved to be particularly tricky to get
+right. In the case of here documents which are not subject to
+variable and command substitution, the parser doesn't insert any
+CTLESC characters to begin with (so the contents of the text
+field can be written without any processing). Other here docu-
+ments, and words which are not subject to splitting and file name
+generation, have the CTLESC characters removed during the vari-
+able and command substitution phase. Words which are subject
+splitting and file name generation have the CTLESC characters re-
+moved as part of the file name phase.
+
+EXECUTION: Command execution is handled by the following files:
+ eval.c The top level routines.
+ redir.c Code to handle redirection of input and output.
+ jobs.c Code to handle forking, waiting, and job control.
+ exec.c Code to to path searches and the actual exec sys call.
+ expand.c Code to evaluate arguments.
+ var.c Maintains the variable symbol table. Called from expand.c.
+
+EVAL.C: Evaltree recursively executes a parse tree. The exit
+status is returned in the global variable exitstatus. The alter-
+native entry evalbackcmd is called to evaluate commands in back
+quotes. It saves the result in memory if the command is a buil-
+tin; otherwise it forks off a child to execute the command and
+connects the standard output of the child to a pipe.
+
+JOBS.C: To create a process, you call makejob to return a job
+structure, and then call forkshell (passing the job structure as
+an argument) to create the process. Waitforjob waits for a job
+to complete. These routines take care of process groups if job
+control is defined.
+
+REDIR.C: Ash allows file descriptors to be redirected and then
+restored without forking off a child process. This is accom-
+plished by duplicating the original file descriptors. The redir-
+tab structure records where the file descriptors have be dupli-
+cated to.
+
+EXEC.C: The routine find_command locates a command, and enters
+the command in the hash table if it is not already there. The
+third argument specifies whether it is to print an error message
+if the command is not found. (When a pipeline is set up,
+find_command is called for all the commands in the pipeline be-
+fore any forking is done, so to get the commands into the hash
+table of the parent process. But to make command hashing as
+transparent as possible, we silently ignore errors at that point
+and only print error messages if the command cannot be found
+later.)
+
+The routine shellexec is the interface to the exec system call.
+
+EXPAND.C: Arguments are processed in three passes. The first
+(performed by the routine argstr) performs variable and command
+substitution. The second (ifsbreakup) performs word splitting
+and the third (expandmeta) performs file name generation. If the
+"/u" directory is simulated, then when "/u/username" is replaced
+by the user's home directory, the flag "didudir" is set. This
+tells the cd command that it should print out the directory name,
+just as it would if the "/u" directory were implemented using
+symbolic links.
+
+VAR.C: Variables are stored in a hash table. Probably we should
+switch to extensible hashing. The variable name is stored in the
+same string as the value (using the format "name=value") so that
+no string copying is needed to create the environment of a com-
+mand. Variables which the shell references internally are preal-
+located so that the shell can reference the values of these vari-
+ables without doing a lookup.
+
+When a program is run, the code in eval.c sticks any environment
+variables which precede the command (as in "PATH=xxx command") in
+the variable table as the simplest way to strip duplicates, and
+then calls "environment" to get the value of the environment.
+There are two consequences of this. First, if an assignment to
+PATH precedes the command, the value of PATH before the assign-
+ment must be remembered and passed to shellexec. Second, if the
+program turns out to be a shell procedure, the strings from the
+environment variables which preceded the command must be pulled
+out of the table and replaced with strings obtained from malloc,
+since the former will automatically be freed when the stack (see
+the entry on memalloc.c) is emptied.
+
+BUILTIN COMMANDS: The procedures for handling these are scat-
+tered throughout the code, depending on which location appears
+most appropriate. They can be recognized because their names al-
+ways end in "cmd". The mapping from names to procedures is
+specified in the file builtins, which is processed by the mkbuil-
+tins command.
+
+A builtin command is invoked with argc and argv set up like a
+normal program. A builtin command is allowed to overwrite its
+arguments. Builtin routines can call nextopt to do option pars-
+ing. This is kind of like getopt, but you don't pass argc and
+argv to it. Builtin routines can also call error. This routine
+normally terminates the shell (or returns to the main command
+loop if the shell is interactive), but when called from a builtin
+command it causes the builtin command to terminate with an exit
+status of 2.
+
+The directory bltins contains commands which can be compiled in-
+dependently but can also be built into the shell for efficiency
+reasons. The makefile in this directory compiles these programs
+in the normal fashion (so that they can be run regardless of
+whether the invoker is ash), but also creates a library named
+bltinlib.a which can be linked with ash. The header file bltin.h
+takes care of most of the differences between the ash and the
+stand-alone environment. The user should call the main routine
+"main", and #define main to be the name of the routine to use
+when the program is linked into ash. This #define should appear
+before bltin.h is included; bltin.h will #undef main if the pro-
+gram is to be compiled stand-alone.
+
+CD.C: This file defines the cd and pwd builtins. The pwd com-
+mand runs /bin/pwd the first time it is invoked (unless the user
+has already done a cd to an absolute pathname), but then
+remembers the current directory and updates it when the cd com-
+mand is run, so subsequent pwd commands run very fast. The main
+complication in the cd command is in the docd command, which
+resolves symbolic links into actual names and informs the user
+where the user ended up if he crossed a symbolic link.
+
+SIGNALS: Trap.c implements the trap command. The routine set-
+signal figures out what action should be taken when a signal is
+received and invokes the signal system call to set the signal ac-
+tion appropriately. When a signal that a user has set a trap for
+is caught, the routine "onsig" sets a flag. The routine dotrap
+is called at appropriate points to actually handle the signal.
+When an interrupt is caught and no trap has been set for that
+signal, the routine "onint" in error.c is called.
+
+OUTPUT: Ash uses it's own output routines. There are three out-
+put structures allocated. "Output" represents the standard out-
+put, "errout" the standard error, and "memout" contains output
+which is to be stored in memory. This last is used when a buil-
+tin command appears in backquotes, to allow its output to be col-
+lected without doing any I/O through the UNIX operating system.
+The variables out1 and out2 normally point to output and errout,
+respectively, but they are set to point to memout when appropri-
+ate inside backquotes.
+
+INPUT: The basic input routine is pgetc, which reads from the
+current input file. There is a stack of input files; the current
+input file is the top file on this stack. The code allows the
+input to come from a string rather than a file. (This is for the
+-c option and the "." and eval builtin commands.) The global
+variable plinno is saved and restored when files are pushed and
+popped from the stack. The parser routines store the number of
+the current line in this variable.
+
+DEBUGGING: If DEBUG is defined in shell.h, then the shell will
+write debugging information to the file $HOME/trace. Most of
+this is done using the TRACE macro, which takes a set of printf
+arguments inside two sets of parenthesis. Example:
+"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
+cause the preprocessor can't handle functions with a variable
+number of arguments. Defining DEBUG also causes the shell to
+generate a core dump if it is sent a quit signal. The tracing
+code is in show.c.
diff --git a/usr/dash/alias.c b/usr/dash/alias.c
new file mode 100644
index 0000000..daeacbb
--- /dev/null
+++ b/usr/dash/alias.c
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "input.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h" /* XXX for argptr (should remove?) */
+
+#define ATABSIZE 39
+
+struct alias *atab[ATABSIZE];
+
+STATIC void setalias(const char *, const char *);
+STATIC struct alias *freealias(struct alias *);
+STATIC struct alias **__lookupalias(const char *);
+
+STATIC
+void
+setalias(const char *name, const char *val)
+{
+ struct alias *ap, **app;
+
+ app = __lookupalias(name);
+ ap = *app;
+ INTOFF;
+ if (ap) {
+ if (!(ap->flag & ALIASINUSE)) {
+ ckfree(ap->val);
+ }
+ ap->val = savestr(val);
+ ap->flag &= ~ALIASDEAD;
+ } else {
+ /* not found */
+ ap = ckmalloc(sizeof (struct alias));
+ ap->name = savestr(name);
+ ap->val = savestr(val);
+ ap->flag = 0;
+ ap->next = 0;
+ *app = ap;
+ }
+ INTON;
+}
+
+int
+unalias(const char *name)
+{
+ struct alias **app;
+
+ app = __lookupalias(name);
+
+ if (*app) {
+ INTOFF;
+ *app = freealias(*app);
+ INTON;
+ return (0);
+ }
+
+ return (1);
+}
+
+void
+rmaliases(void)
+{
+ struct alias *ap, **app;
+ int i;
+
+ INTOFF;
+ for (i = 0; i < ATABSIZE; i++) {
+ app = &atab[i];
+ for (ap = *app; ap; ap = *app) {
+ *app = freealias(*app);
+ if (ap == *app) {
+ app = &ap->next;
+ }
+ }
+ }
+ INTON;
+}
+
+struct alias *
+lookupalias(const char *name, int check)
+{
+ struct alias *ap = *__lookupalias(name);
+
+ if (check && ap && (ap->flag & ALIASINUSE))
+ return (NULL);
+ return (ap);
+}
+
+/*
+ * TODO - sort output
+ */
+int
+aliascmd(int argc, char **argv)
+{
+ char *n, *v;
+ int ret = 0;
+ struct alias *ap;
+
+ if (argc == 1) {
+ int i;
+
+ for (i = 0; i < ATABSIZE; i++)
+ for (ap = atab[i]; ap; ap = ap->next) {
+ printalias(ap);
+ }
+ return (0);
+ }
+ while ((n = *++argv) != NULL) {
+ if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
+ if ((ap = *__lookupalias(n)) == NULL) {
+ outfmt(out2, "%s: %s not found\n", "alias", n);
+ ret = 1;
+ } else
+ printalias(ap);
+ } else {
+ *v++ = '\0';
+ setalias(n, v);
+ }
+ }
+
+ return (ret);
+}
+
+int
+unaliascmd(int argc, char **argv)
+{
+ int i;
+
+ while ((i = nextopt("a")) != '\0') {
+ if (i == 'a') {
+ rmaliases();
+ return (0);
+ }
+ }
+ for (i = 0; *argptr; argptr++) {
+ if (unalias(*argptr)) {
+ outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
+ i = 1;
+ }
+ }
+
+ return (i);
+}
+
+STATIC struct alias *
+freealias(struct alias *ap) {
+ struct alias *next;
+
+ if (ap->flag & ALIASINUSE) {
+ ap->flag |= ALIASDEAD;
+ return ap;
+ }
+
+ next = ap->next;
+ ckfree(ap->name);
+ ckfree(ap->val);
+ ckfree(ap);
+ return next;
+}
+
+void
+printalias(const struct alias *ap) {
+ out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
+}
+
+STATIC struct alias **
+__lookupalias(const char *name) {
+ unsigned int hashval;
+ struct alias **app;
+ const char *p;
+ unsigned int ch;
+
+ p = name;
+
+ ch = (unsigned char)*p;
+ hashval = ch << 4;
+ while (ch) {
+ hashval += ch;
+ ch = (unsigned char)*++p;
+ }
+ app = &atab[hashval % ATABSIZE];
+
+ for (; *app; app = &(*app)->next) {
+ if (equal(name, (*app)->name)) {
+ break;
+ }
+ }
+
+ return app;
+}
diff --git a/usr/dash/alias.h b/usr/dash/alias.h
new file mode 100644
index 0000000..fb841d6
--- /dev/null
+++ b/usr/dash/alias.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)alias.h 8.2 (Berkeley) 5/4/95
+ */
+
+#define ALIASINUSE 1
+#define ALIASDEAD 2
+
+struct alias {
+ struct alias *next;
+ char *name;
+ char *val;
+ int flag;
+};
+
+struct alias *lookupalias(const char *, int);
+int aliascmd(int, char **);
+int unaliascmd(int, char **);
+void rmaliases(void);
+int unalias(const char *);
+void printalias(const struct alias *);
diff --git a/usr/dash/arith_yacc.c b/usr/dash/arith_yacc.c
new file mode 100644
index 0000000..1a087c3
--- /dev/null
+++ b/usr/dash/arith_yacc.c
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include "arith_yacc.h"
+#include "expand.h"
+#include "shell.h"
+#include "error.h"
+#include "output.h"
+#include "var.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+static const char *arith_startbuf;
+
+const char *arith_buf;
+union yystype yylval;
+
+static int last_token;
+
+#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
+
+static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
+ ARITH_PRECEDENCE(ARITH_MUL, 0),
+ ARITH_PRECEDENCE(ARITH_DIV, 0),
+ ARITH_PRECEDENCE(ARITH_REM, 0),
+ ARITH_PRECEDENCE(ARITH_ADD, 1),
+ ARITH_PRECEDENCE(ARITH_SUB, 1),
+ ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_LT, 3),
+ ARITH_PRECEDENCE(ARITH_LE, 3),
+ ARITH_PRECEDENCE(ARITH_GT, 3),
+ ARITH_PRECEDENCE(ARITH_GE, 3),
+ ARITH_PRECEDENCE(ARITH_EQ, 4),
+ ARITH_PRECEDENCE(ARITH_NE, 4),
+ ARITH_PRECEDENCE(ARITH_BAND, 5),
+ ARITH_PRECEDENCE(ARITH_BXOR, 6),
+ ARITH_PRECEDENCE(ARITH_BOR, 7),
+};
+
+#define ARITH_MAX_PREC 8
+
+static void yyerror(const char *s) __attribute__ ((noreturn));
+static void yyerror(const char *s)
+{
+ sh_error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+ /* NOTREACHED */
+}
+
+static inline int arith_prec(int op)
+{
+ return prec[op - ARITH_BINOP_MIN];
+}
+
+static inline int higher_prec(int op1, int op2)
+{
+ return arith_prec(op1) < arith_prec(op2);
+}
+
+static intmax_t do_binop(int op, intmax_t a, intmax_t b)
+{
+ switch (op) {
+ default:
+ case ARITH_REM:
+ case ARITH_DIV:
+ if (!b)
+ yyerror("division by zero");
+ return op == ARITH_REM ? a % b : a / b;
+ case ARITH_MUL:
+ return a * b;
+ case ARITH_ADD:
+ return a + b;
+ case ARITH_SUB:
+ return a - b;
+ case ARITH_LSHIFT:
+ return a << b;
+ case ARITH_RSHIFT:
+ return a >> b;
+ case ARITH_LT:
+ return a < b;
+ case ARITH_LE:
+ return a <= b;
+ case ARITH_GT:
+ return a > b;
+ case ARITH_GE:
+ return a >= b;
+ case ARITH_EQ:
+ return a == b;
+ case ARITH_NE:
+ return a != b;
+ case ARITH_BAND:
+ return a & b;
+ case ARITH_BXOR:
+ return a ^ b;
+ case ARITH_BOR:
+ return a | b;
+ }
+}
+
+static intmax_t assignment(int var, int noeval);
+
+static intmax_t primary(int token, union yystype *val, int op, int noeval)
+{
+ intmax_t result;
+
+again:
+ switch (token) {
+ case ARITH_LPAREN:
+ result = assignment(op, noeval);
+ if (last_token != ARITH_RPAREN)
+ yyerror("expecting ')'");
+ last_token = yylex();
+ return result;
+ case ARITH_NUM:
+ last_token = op;
+ return val->val;
+ case ARITH_VAR:
+ last_token = op;
+ return noeval ? val->val : lookupvarint(val->name);
+ case ARITH_ADD:
+ token = op;
+ *val = yylval;
+ op = yylex();
+ goto again;
+ case ARITH_SUB:
+ *val = yylval;
+ return -primary(op, val, yylex(), noeval);
+ case ARITH_NOT:
+ *val = yylval;
+ return !primary(op, val, yylex(), noeval);
+ case ARITH_BNOT:
+ *val = yylval;
+ return ~primary(op, val, yylex(), noeval);
+ default:
+ yyerror("expecting primary");
+ }
+}
+
+static intmax_t binop2(intmax_t a, int op, int prec, int noeval)
+{
+ for (;;) {
+ union yystype val;
+ intmax_t b;
+ int op2;
+ int token;
+
+ token = yylex();
+ val = yylval;
+
+ b = primary(token, &val, yylex(), noeval);
+
+ op2 = last_token;
+ if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
+ higher_prec(op2, op)) {
+ b = binop2(b, op2, arith_prec(op), noeval);
+ op2 = last_token;
+ }
+
+ a = noeval ? b : do_binop(op, a, b);
+
+ if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
+ arith_prec(op2) >= prec)
+ return a;
+
+ op = op2;
+ }
+}
+
+static intmax_t binop(int token, union yystype *val, int op, int noeval)
+{
+ intmax_t a = primary(token, val, op, noeval);
+
+ op = last_token;
+ if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
+ return a;
+
+ return binop2(a, op, ARITH_MAX_PREC, noeval);
+}
+
+static intmax_t and(int token, union yystype *val, int op, int noeval)
+{
+ intmax_t a = binop(token, val, op, noeval);
+ intmax_t b;
+
+ op = last_token;
+ if (op != ARITH_AND)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = and(token, val, yylex(), noeval | !a);
+
+ return a && b;
+}
+
+static intmax_t or(int token, union yystype *val, int op, int noeval)
+{
+ intmax_t a = and(token, val, op, noeval);
+ intmax_t b;
+
+ op = last_token;
+ if (op != ARITH_OR)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = or(token, val, yylex(), noeval | !!a);
+
+ return a || b;
+}
+
+static intmax_t cond(int token, union yystype *val, int op, int noeval)
+{
+ intmax_t a = or(token, val, op, noeval);
+ intmax_t b;
+ intmax_t c;
+
+ if (last_token != ARITH_QMARK)
+ return a;
+
+ b = assignment(yylex(), noeval | !a);
+
+ if (last_token != ARITH_COLON)
+ yyerror("expecting ':'");
+
+ token = yylex();
+ *val = yylval;
+
+ c = cond(token, val, yylex(), noeval | !!a);
+
+ return a ? b : c;
+}
+
+static intmax_t assignment(int var, int noeval)
+{
+ union yystype val = yylval;
+ int op = yylex();
+ intmax_t result;
+
+ if (var != ARITH_VAR)
+ return cond(var, &val, op, noeval);
+
+ if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
+ return cond(var, &val, op, noeval);
+
+ result = assignment(yylex(), noeval);
+ if (noeval)
+ return result;
+
+ return setvarint(val.name,
+ op == ARITH_ASS ? result :
+ do_binop(op - 11, lookupvarint(val.name), result), 0);
+}
+
+intmax_t arith(const char *s)
+{
+ intmax_t result;
+
+ arith_buf = arith_startbuf = s;
+
+ result = assignment(yylex(), 0);
+
+ if (last_token)
+ yyerror("expecting EOF");
+
+ return result;
+}
diff --git a/usr/dash/arith_yacc.h b/usr/dash/arith_yacc.h
new file mode 100644
index 0000000..ff34d52
--- /dev/null
+++ b/usr/dash/arith_yacc.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 ARITH_ASS 1
+
+#define ARITH_OR 2
+#define ARITH_AND 3
+#define ARITH_BAD 4
+#define ARITH_NUM 5
+#define ARITH_VAR 6
+#define ARITH_NOT 7
+
+#define ARITH_BINOP_MIN 8
+#define ARITH_LE 8
+#define ARITH_GE 9
+#define ARITH_LT 10
+#define ARITH_GT 11
+#define ARITH_EQ 12
+#define ARITH_REM 13
+#define ARITH_BAND 14
+#define ARITH_LSHIFT 15
+#define ARITH_RSHIFT 16
+#define ARITH_MUL 17
+#define ARITH_ADD 18
+#define ARITH_BOR 19
+#define ARITH_SUB 20
+#define ARITH_BXOR 21
+#define ARITH_DIV 22
+#define ARITH_NE 23
+#define ARITH_BINOP_MAX 24
+
+#define ARITH_ASS_MIN 24
+#define ARITH_REMASS 24
+#define ARITH_BANDASS 25
+#define ARITH_LSHIFTASS 26
+#define ARITH_RSHIFTASS 27
+#define ARITH_MULASS 28
+#define ARITH_ADDASS 29
+#define ARITH_BORASS 30
+#define ARITH_SUBASS 31
+#define ARITH_BXORASS 32
+#define ARITH_DIVASS 33
+#define ARITH_ASS_MAX 34
+
+#define ARITH_LPAREN 34
+#define ARITH_RPAREN 35
+#define ARITH_BNOT 36
+#define ARITH_QMARK 37
+#define ARITH_COLON 38
+
+union yystype {
+ intmax_t val;
+ char *name;
+};
+
+extern union yystype yylval;
+
+int yylex(void);
diff --git a/usr/dash/arith_yylex.c b/usr/dash/arith_yylex.c
new file mode 100644
index 0000000..ec5b5b2
--- /dev/null
+++ b/usr/dash/arith_yylex.c
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2002
+ * Herbert Xu.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "arith_yacc.h"
+#include "expand.h"
+#include "error.h"
+#include "shell.h"
+#include "memalloc.h"
+#include "syntax.h"
+#include "system.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+extern const char *arith_buf;
+
+int
+yylex()
+{
+ int value;
+ const char *buf = arith_buf;
+ const char *p;
+
+ for (;;) {
+ value = *buf;
+ switch (value) {
+ case ' ':
+ case '\t':
+ case '\n':
+ buf++;
+ continue;
+ default:
+ return ARITH_BAD;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ yylval.val = strtoimax(buf, (char **)&arith_buf, 0);
+ return ARITH_NUM;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ p = buf;
+ while (buf++, is_in_name(*buf))
+ ;
+ yylval.name = stalloc(buf - p + 1);
+ *(char *)mempcpy(yylval.name, p, buf - p) = 0;
+ value = ARITH_VAR;
+ goto out;
+ case '=':
+ value += ARITH_ASS - '=';
+checkeq:
+ buf++;
+checkeqcur:
+ if (*buf != '=')
+ goto out;
+ value += 11;
+ break;
+ case '>':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_GE - '>';
+ break;
+ case '>':
+ value += ARITH_RSHIFT - '>';
+ goto checkeq;
+ default:
+ value += ARITH_GT - '>';
+ goto out;
+ }
+ break;
+ case '<':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_LE - '<';
+ break;
+ case '<':
+ value += ARITH_LSHIFT - '<';
+ goto checkeq;
+ default:
+ value += ARITH_LT - '<';
+ goto out;
+ }
+ break;
+ case '|':
+ if (*++buf != '|') {
+ value += ARITH_BOR - '|';
+ goto checkeqcur;
+ }
+ value += ARITH_OR - '|';
+ break;
+ case '&':
+ if (*++buf != '&') {
+ value += ARITH_BAND - '&';
+ goto checkeqcur;
+ }
+ value += ARITH_AND - '&';
+ break;
+ case '!':
+ if (*++buf != '=') {
+ value += ARITH_NOT - '!';
+ goto out;
+ }
+ value += ARITH_NE - '!';
+ break;
+ case 0:
+ goto out;
+ case '(':
+ value += ARITH_LPAREN - '(';
+ break;
+ case ')':
+ value += ARITH_RPAREN - ')';
+ break;
+ case '*':
+ value += ARITH_MUL - '*';
+ goto checkeq;
+ case '/':
+ value += ARITH_DIV - '/';
+ goto checkeq;
+ case '%':
+ value += ARITH_REM - '%';
+ goto checkeq;
+ case '+':
+ value += ARITH_ADD - '+';
+ goto checkeq;
+ case '-':
+ value += ARITH_SUB - '-';
+ goto checkeq;
+ case '~':
+ value += ARITH_BNOT - '~';
+ break;
+ case '^':
+ value += ARITH_BXOR - '^';
+ goto checkeq;
+ case '?':
+ value += ARITH_QMARK - '?';
+ break;
+ case ':':
+ value += ARITH_COLON - ':';
+ break;
+ }
+ break;
+ }
+
+ buf++;
+out:
+ arith_buf = buf;
+ return value;
+}
diff --git a/usr/dash/bltin/bltin.h b/usr/dash/bltin/bltin.h
new file mode 100644
index 0000000..f5ac06f
--- /dev/null
+++ b/usr/dash/bltin/bltin.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bltin.h 8.1 (Berkeley) 5/31/93
+ */
+
+/*
+ * This file is included by programs which are optionally built into the
+ * shell. If SHELL is defined, we try to map the standard UNIX library
+ * routines to ash routines using defines.
+ */
+
+#include "../shell.h"
+#include "../mystring.h"
+#include "../options.h"
+#ifdef SHELL
+#include "../memalloc.h"
+#include "../output.h"
+#include "../error.h"
+#ifndef USE_GLIBC_STDIO
+#undef stdout
+#undef stderr
+#undef putc
+#undef putchar
+#undef fileno
+#define stdout out1
+#define stderr out2
+#define printf out1fmt
+#define putc(c, file) outc(c, file)
+#define putchar(c) out1c(c)
+#define FILE struct output
+#define fprintf outfmt
+#define fputs outstr
+#define fflush flushout
+#define fileno(f) ((f)->fd)
+#define ferror outerr
+#endif
+#define INITARGS(argv)
+#define error sh_error
+#define warn sh_warn
+#define warnx sh_warnx
+#define exit sh_exit
+#define setprogname(s)
+#define getprogname() commandname
+#define setlocate(l,s) 0
+
+#define getenv(p) bltinlookup((p),0)
+
+#else
+#undef NULL
+#include <stdio.h>
+#undef main
+#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#endif
+
+int echocmd(int, char **);
+
+
+extern const char *commandname;
diff --git a/usr/dash/bltin/echo.1 b/usr/dash/bltin/echo.1
new file mode 100644
index 0000000..fbc7fb4
--- /dev/null
+++ b/usr/dash/bltin/echo.1
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1997-2005
+.\" Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\" Copyright 1989 by Kenneth Almquist
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)echo.1 8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt ECHO 1
+.Os
+.Sh NAME
+.Nm echo
+.Nd produce message in a shell script
+.Sh SYNOPSIS
+.Nm
+.Op Fl n | Fl e
+.Ar args ...
+.Sh DESCRIPTION
+.Nm
+prints its arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+The
+.Fl e
+option causes
+.Nm
+to treat the escape sequences specially, as described in the following
+paragraph.
+The
+.Fl e
+option is the default, and is provided solely for compatibility with
+other systems.
+Only one of the options
+.Fl n
+and
+.Fl e
+may be given.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output. Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed. This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Nm
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Sh HINTS
+Remember that backslash is special to the shell and needs to be escaped.
+To output a message to standard error, say
+.Pp
+.D1 echo message \*[Gt]\*[Am]2
+.Sh BUGS
+The octal character escape mechanism
+.Pq Li \e0 Ns Ar digits
+differs from the
+C language mechanism.
+.Pp
+There is no way to force
+.Nm
+to treat its arguments literally, rather than interpreting them as
+options and escape sequences.
diff --git a/usr/dash/bltin/printf.1 b/usr/dash/bltin/printf.1
new file mode 100644
index 0000000..b1265a5
--- /dev/null
+++ b/usr/dash/bltin/printf.1
@@ -0,0 +1,354 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1997-2005
+.\" Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)printf.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd November 5, 1993
+.Dt PRINTF 1
+.Os
+.Sh NAME
+.Nm printf
+.Nd formatted output
+.Sh SYNOPSIS
+.Nm
+.Ar format
+.Op Ar arguments ...
+.Sh DESCRIPTION
+.Nm
+formats and prints its arguments, after the first, under control
+of the
+.Ar format .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm b ,
+.Cm B ,
+.Cm c
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+.Tn ASCII
+code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in
+.St -ansiC .
+The characters and their meanings are as follows:
+.Bl -tag -width Ds -offset indent
+.It Cm \ee
+Write an \*[Lt]escape\*[Gt] character.
+.It Cm \ea
+Write a \*[Lt]bell\*[Gt] character.
+.It Cm \eb
+Write a \*[Lt]backspace\*[Gt] character.
+.It Cm \ef
+Write a \*[Lt]form-feed\*[Gt] character.
+.It Cm \en
+Write a \*[Lt]new-line\*[Gt] character.
+.It Cm \er
+Write a \*[Lt]carriage return\*[Gt] character.
+.It Cm \et
+Write a \*[Lt]tab\*[Gt] character.
+.It Cm \ev
+Write a \*[Lt]vertical tab\*[Gt] character.
+.It Cm \e\'
+Write a \*[Lt]single quote\*[Gt] character.
+.It Cm \e"
+Write a \*[Lt]double quote\*[Gt] character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit octal number
+.Ar num .
+.It Cm \ex Ns Ar xx
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\- or 2\-digit hexadecimal number
+.Ar xx .
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternative form''.
+For
+.Cm b ,
+.Cm c ,
+.Cm d ,
+and
+.Cm s
+formats, this option has no effect.
+For the
+.Cm o
+format the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm e ,
+.Cm E ,
+.Cm f ,
+.Cm g ,
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be.
+.\" I turned this off - decided it isn't a valid use of '#'
+.\" For the
+.\" .Cm B
+.\" format, backslash-escape sequences are expanded first;
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer characters than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision :
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of characters to be printed
+from a string
+.Sm off
+.Pf ( Cm b No ,
+.Sm on
+.Cm B
+and
+.Cm s
+formats); if the digit string is missing, the precision is treated
+as zero;
+.It Format :
+A character which indicates the type of format to use (one of
+.Cm diouxXfwEgGbBcs ) .
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm f
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]ddd Cm \&. No ddd
+.Sm on
+where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+An upper-case E is used for an `E' format.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm b
+Characters from the string
+.Ar argument
+are printed with backslash-escape sequences expanded.
+.br
+The following additional backslash-escape sequences are supported:
+.Bl -tag -width Ds
+.It Cm \ec
+Causes
+.Nm
+to ignore any remaining characters in the string operand containing it,
+any remaining string operands, and any additional characters in
+the format operand.
+.It Cm \e0 Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.It Cm \e^ Ns Ar c
+Write the control character
+.Ar c .
+Generates characters `\e000' through `\e037`, and `\e177' (from `\e^?').
+.It Cm \eM\- Ns Ar c
+Write the character
+.Ar c
+with the 8th bit set.
+Generates characters `\e241' through `\e376`.
+.It Cm \eM^ Ns Ar c
+Write the control character
+.Ar c
+with the 8th bit set.
+Generates characters `\e000' through `\e037`, and `\e177' (from `\eM^?').
+.El
+.It Cm B
+Characters from the string
+.Ar argument
+are printed with unprintable characters backslash-escaped using the
+.Sm off
+.Pf ` Cm \e Ar c No ',
+.Pf ` Cm \e^ Ar c No ',
+.Pf ` Cm \eM\- Ar c No '
+or
+.Pf ` Cm \eM^ Ar c No ',
+.Sm on
+formats described above.
+.It Cm c
+The first character of
+.Ar argument
+is printed.
+.It Cm s
+Characters from the string
+.Ar argument
+are printed until the end is reached or until the number of characters
+indicated by the precision specification is reached; if the
+precision is omitted, all characters in the string are printed.
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.Sh EXIT STATUS
+.Nm
+exits 0 on success, 1 on failure.
+.Sh SEE ALSO
+.Xr echo 1 ,
+.Xr printf 3 ,
+.Xr printf 9
+.Xr vis 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Pp
+Support for the floating point formats and `*' as a field width and precision
+are optional in POSIX.
+.Pp
+The behaviour of the %B format and the \e', \e", \exxx, \ee and
+\e[M][\-|^]c escape sequences are undefined in POSIX.
+.Sh BUGS
+Since the floating point numbers are translated from
+.Tn ASCII
+to floating-point and
+then back again, floating-point precision may be lost.
+.Pp
+Hexadecimal character constants are restricted to, and should be specified
+as, two character constants. This is contrary to the ISO C standard but
+does guarantee detection of the end of the constant.
diff --git a/usr/dash/bltin/printf.c b/usr/dash/bltin/printf.c
new file mode 100644
index 0000000..b32b54f
--- /dev/null
+++ b/usr/dash/bltin/printf.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE 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 <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int conv_escape_str(char *);
+static char *conv_escape(char *, int *);
+static int getchr(void);
+static intmax_t getintmax(void);
+static uintmax_t getuintmax(void);
+static char *getstr(void);
+static char *mklong(const char *, const char *);
+static void check_conversion(const char *, const char *);
+#ifdef HAVE_STRTOD
+static double getdouble(void);
+#endif
+
+static int rval;
+static char **gargv;
+
+#define isodigit(c) ((c) >= '0' && (c) <= '7')
+#define octtobin(c) ((c) - '0')
+
+#include "bltin.h"
+#include "system.h"
+
+#define PF(f, func) { \
+ switch ((char *)param - (char *)array) { \
+ default: \
+ (void)printf(f, array[0], array[1], func); \
+ break; \
+ case sizeof(*param): \
+ (void)printf(f, array[0], func); \
+ break; \
+ case 0: \
+ (void)printf(f, func); \
+ break; \
+ } \
+}
+
+int printfcmd(int argc, char *argv[])
+{
+ char *fmt;
+ char *format;
+ int ch;
+
+ rval = 0;
+
+ nextopt(nullstr);
+
+ argv = argptr;
+ format = *argv;
+
+ if (!format) {
+ warnx("usage: printf format [arg ...]");
+ goto err;
+ }
+
+ gargv = ++argv;
+
+#define SKIP1 "#-+ 0"
+#define SKIP2 "*0123456789"
+ do {
+ /*
+ * Basic algorithm is to scan the format string for conversion
+ * specifications -- once one is found, find out if the field
+ * width or precision is a '*'; if it is, gather up value.
+ * Note, format strings are reused as necessary to use up the
+ * provided arguments, arguments of zero/null string are
+ * provided to use up the format string.
+ */
+
+ /* find next format specification */
+ for (fmt = format; (ch = *fmt++) ;) {
+ char *start;
+ char nextch;
+ int array[2];
+ int *param;
+
+ if (ch == '\\') {
+ int c_ch;
+ fmt = conv_escape(fmt, &c_ch);
+ ch = c_ch;
+ goto pc;
+ }
+ if (ch != '%' || (*fmt == '%' && (++fmt || 1))) {
+pc:
+ putchar(ch);
+ continue;
+ }
+
+ /* Ok - we've found a format specification,
+ Save its address for a later printf(). */
+ start = fmt - 1;
+ param = array;
+
+ /* skip to field width */
+ fmt += strspn(fmt, SKIP1);
+ if (*fmt == '*')
+ *param++ = getintmax();
+
+ /* skip to possible '.', get following precision */
+ fmt += strspn(fmt, SKIP2);
+ if (*fmt == '.')
+ ++fmt;
+ if (*fmt == '*')
+ *param++ = getintmax();
+
+ fmt += strspn(fmt, SKIP2);
+
+ ch = *fmt;
+ if (!ch) {
+ warnx("missing format character");
+ goto err;
+ }
+ /* null terminate format string to we can use it
+ as an argument to printf. */
+ nextch = fmt[1];
+ fmt[1] = 0;
+ switch (ch) {
+
+ case 'b': {
+ int done = conv_escape_str(getstr());
+ char *p = stackblock();
+ *fmt = 's';
+ PF(start, p);
+ /* escape if a \c was encountered */
+ if (done)
+ goto out;
+ *fmt = 'b';
+ break;
+ }
+ case 'c': {
+ int p = getchr();
+ PF(start, p);
+ break;
+ }
+ case 's': {
+ char *p = getstr();
+ PF(start, p);
+ break;
+ }
+ case 'd':
+ case 'i': {
+ intmax_t p = getintmax();
+ char *f = mklong(start, fmt);
+ PF(f, p);
+ break;
+ }
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X': {
+ uintmax_t p = getuintmax();
+ char *f = mklong(start, fmt);
+ PF(f, p);
+ break;
+ }
+#ifdef HAVE_STRTOD
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G': {
+ double p = getdouble();
+ PF(start, p);
+ break;
+ }
+#endif
+ default:
+ warnx("%s: invalid directive", start);
+ goto err;
+ }
+ *++fmt = nextch;
+ }
+ } while (gargv != argv && *gargv);
+
+out:
+ return rval;
+err:
+ return 1;
+}
+
+
+/*
+ * Print SysV echo(1) style escape string
+ * Halts processing string if a \c escape is encountered.
+ */
+static int
+conv_escape_str(char *str)
+{
+ int ch;
+ char *cp;
+
+ /* convert string into a temporary buffer... */
+ STARTSTACKSTR(cp);
+
+ do {
+ int c;
+
+ ch = *str++;
+ if (ch != '\\')
+ continue;
+
+ ch = *str++;
+ if (ch == 'c') {
+ /* \c as in SYSV echo - abort all processing.... */
+ ch = 0x100;
+ continue;
+ }
+
+ /*
+ * %b string octal constants are not like those in C.
+ * They start with a \0, and are followed by 0, 1, 2,
+ * or 3 octal digits.
+ */
+ if (ch == '0') {
+ unsigned char i;
+ i = 3;
+ ch = 0;
+ do {
+ unsigned k = octtobin(*str);
+ if (k > 7)
+ break;
+ str++;
+ ch <<= 3;
+ ch += k;
+ } while (--i);
+ continue;
+ }
+
+ /* Finally test for sequences valid in the format string */
+ str = conv_escape(str - 1, &c);
+ ch = c;
+ } while (STPUTC(ch, cp), (char)ch);
+
+ return ch;
+}
+
+/*
+ * Print "standard" escape characters
+ */
+static char *
+conv_escape(char *str, int *conv_ch)
+{
+ int value;
+ int ch;
+
+ ch = *str;
+
+ switch (ch) {
+ default:
+ case 0:
+ value = '\\';
+ goto out;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ ch = 3;
+ value = 0;
+ do {
+ value <<= 3;
+ value += octtobin(*str++);
+ } while (isodigit(*str) && --ch);
+ goto out;
+
+ case '\\': value = '\\'; break; /* backslash */
+ case 'a': value = '\a'; break; /* alert */
+ case 'b': value = '\b'; break; /* backspace */
+ case 'f': value = '\f'; break; /* form-feed */
+ case 'n': value = '\n'; break; /* newline */
+ case 'r': value = '\r'; break; /* carriage-return */
+ case 't': value = '\t'; break; /* tab */
+ case 'v': value = '\v'; break; /* vertical-tab */
+ }
+
+ str++;
+out:
+ *conv_ch = value;
+ return str;
+}
+
+static char *
+mklong(const char *str, const char *ch)
+{
+ char *copy;
+ size_t len;
+
+ len = ch - str + 3;
+ STARTSTACKSTR(copy);
+ copy = makestrspace(len, copy);
+ memcpy(copy, str, len - 3);
+ copy[len - 3] = 'j';
+ copy[len - 2] = *ch;
+ copy[len - 1] = '\0';
+ return (copy);
+}
+
+static int
+getchr(void)
+{
+ int val = 0;
+
+ if (*gargv)
+ val = **gargv++;
+ return val;
+}
+
+static char *
+getstr(void)
+{
+ char *val = nullstr;
+
+ if (*gargv)
+ val = *gargv++;
+ return val;
+}
+
+static intmax_t
+getintmax(void)
+{
+ intmax_t val = 0;
+ char *cp, *ep;
+
+ cp = *gargv;
+ if (cp == NULL)
+ goto out;
+ gargv++;
+
+ val = (unsigned char) cp[1];
+ if (*cp == '\"' || *cp == '\'')
+ goto out;
+
+ errno = 0;
+ val = strtoimax(cp, &ep, 0);
+ check_conversion(cp, ep);
+out:
+ return val;
+}
+
+static uintmax_t
+getuintmax(void)
+{
+ uintmax_t val = 0;
+ char *cp, *ep;
+
+ cp = *gargv;
+ if (cp == NULL)
+ goto out;
+ gargv++;
+
+ val = (unsigned char) cp[1];
+ if (*cp == '\"' || *cp == '\'')
+ goto out;
+
+ errno = 0;
+ val = strtoumax(cp, &ep, 0);
+ check_conversion(cp, ep);
+out:
+ return val;
+}
+
+#ifdef HAVE_STRTOD
+static double
+getdouble(void)
+{
+ double val;
+ char *cp, *ep;
+
+ cp = *gargv;
+ if (cp == NULL)
+ return 0;
+ gargv++;
+
+ if (*cp == '\"' || *cp == '\'')
+ return (unsigned char) cp[1];
+
+ errno = 0;
+ val = strtod(cp, &ep);
+ check_conversion(cp, ep);
+ return val;
+}
+#endif
+
+static void
+check_conversion(const char *s, const char *ep)
+{
+ if (*ep) {
+ if (ep == s)
+ warnx("%s: expected numeric value", s);
+ else
+ warnx("%s: not completely converted", s);
+ rval = 1;
+ } else if (errno == ERANGE) {
+ warnx("%s: %s", s, strerror(ERANGE));
+ rval = 1;
+ }
+}
+
+int
+echocmd(int argc, char **argv)
+{
+ int nonl = 0;
+ struct output *outs = out1;
+
+ if (!*++argv)
+ goto end;
+ if (equal(*argv, "-n")) {
+ nonl = ~nonl;
+ if (!*++argv)
+ goto end;
+ }
+
+ do {
+ int c;
+
+ nonl += conv_escape_str(*argv);
+ outstr(stackblock(), outs);
+ if (nonl > 0)
+ break;
+
+ c = ' ';
+ if (!*++argv) {
+end:
+ if (nonl) {
+ break;
+ }
+ c = '\n';
+ }
+ outc(c, outs);
+ } while (*argv);
+ return 0;
+}
diff --git a/usr/dash/bltin/test.1 b/usr/dash/bltin/test.1
new file mode 100644
index 0000000..42435fb
--- /dev/null
+++ b/usr/dash/bltin/test.1
@@ -0,0 +1,309 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1997-2005
+.\" Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)test.1 8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt TEST 1
+.Os
+.Sh NAME
+.Nm test ,
+.Nm \&[
+.Nd condition evaluation utility
+.Sh SYNOPSIS
+.Nm test
+.Ar expression
+.Nm \&[
+.Ar expression Cm ]
+.Sh DESCRIPTION
+The
+.Nm test
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression, test also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Nm test
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Po Tn FIFO Pc .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl h
+instead.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar \&s\&1 Cm \&= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are identical.
+.It Ar \&s\&1 Cm \&!= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are not identical.
+.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes before
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes after
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&n\&1 Fl \&eq Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are algebraically
+equal.
+.It Ar \&n\&1 Fl \&ne Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are not
+algebraically equal.
+.It Ar \&n\&1 Fl \&gt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&ge Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than or equal to the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&lt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&le Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than or equal to the integer
+.Ar \&n\&2 .
+.El
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ns Ar expression Ns Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.Sh GRAMMAR AMBIGUITY
+The
+.Nm test
+grammar is inherently ambiguous.
+In order to assure a degree of consistency, the cases described in
+.St -p1003.2
+section 4.62.4,
+are evaluated consistently according to the rules specified in the
+standards document.
+All other cases are subject to the ambiguity in the command semantics.
+.Sh EXIT STATUS
+The
+.Nm test
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 0
+expression evaluated to true.
+.It 1
+expression evaluated to false or expression was
+missing.
+.It \*[Gt]1
+An error occurred.
+.El
+.Sh STANDARDS
+The
+.Nm test
+utility implements a superset of the
+.St -p1003.2
+specification.
diff --git a/usr/dash/bltin/test.c b/usr/dash/bltin/test.c
new file mode 100644
index 0000000..90135e1
--- /dev/null
+++ b/usr/dash/bltin/test.c
@@ -0,0 +1,543 @@
+/*
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "bltin.h"
+
+/* test(1) accepts the following grammar:
+ oexpr ::= aexpr | aexpr "-o" oexpr ;
+ aexpr ::= nexpr | nexpr "-a" aexpr ;
+ nexpr ::= primary | "!" primary
+ primary ::= unary-operator operand
+ | operand binary-operator operand
+ | operand
+ | "(" oexpr ")"
+ ;
+ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ "-nt"|"-ot"|"-ef";
+ operand ::= <any legal UNIX file name>
+*/
+
+enum token {
+ EOI,
+ FILRD,
+ FILWR,
+ FILEX,
+ FILEXIST,
+ FILREG,
+ FILDIR,
+ FILCDEV,
+ FILBDEV,
+ FILFIFO,
+ FILSOCK,
+ FILSYM,
+ FILGZ,
+ FILTT,
+ FILSUID,
+ FILSGID,
+ FILSTCK,
+ FILNT,
+ FILOT,
+ FILEQ,
+ FILUID,
+ FILGID,
+ STREZ,
+ STRNZ,
+ STREQ,
+ STRNE,
+ STRLT,
+ STRGT,
+ INTEQ,
+ INTNE,
+ INTGE,
+ INTGT,
+ INTLE,
+ INTLT,
+ UNOT,
+ BAND,
+ BOR,
+ LPAREN,
+ RPAREN,
+ OPERAND
+};
+
+enum token_types {
+ UNOP,
+ BINOP,
+ BUNOP,
+ BBINOP,
+ PAREN
+};
+
+static struct t_op {
+ const char *op_text;
+ short op_num, op_type;
+} const ops [] = {
+ {"-r", FILRD, UNOP},
+ {"-w", FILWR, UNOP},
+ {"-x", FILEX, UNOP},
+ {"-e", FILEXIST,UNOP},
+ {"-f", FILREG, UNOP},
+ {"-d", FILDIR, UNOP},
+ {"-c", FILCDEV,UNOP},
+ {"-b", FILBDEV,UNOP},
+ {"-p", FILFIFO,UNOP},
+ {"-u", FILSUID,UNOP},
+ {"-g", FILSGID,UNOP},
+ {"-k", FILSTCK,UNOP},
+ {"-s", FILGZ, UNOP},
+ {"-t", FILTT, UNOP},
+ {"-z", STREZ, UNOP},
+ {"-n", STRNZ, UNOP},
+ {"-h", FILSYM, UNOP}, /* for backwards compat */
+ {"-O", FILUID, UNOP},
+ {"-G", FILGID, UNOP},
+ {"-L", FILSYM, UNOP},
+ {"-S", FILSOCK,UNOP},
+ {"=", STREQ, BINOP},
+ {"!=", STRNE, BINOP},
+ {"<", STRLT, BINOP},
+ {">", STRGT, BINOP},
+ {"-eq", INTEQ, BINOP},
+ {"-ne", INTNE, BINOP},
+ {"-ge", INTGE, BINOP},
+ {"-gt", INTGT, BINOP},
+ {"-le", INTLE, BINOP},
+ {"-lt", INTLT, BINOP},
+ {"-nt", FILNT, BINOP},
+ {"-ot", FILOT, BINOP},
+ {"-ef", FILEQ, BINOP},
+ {"!", UNOT, BUNOP},
+ {"-a", BAND, BBINOP},
+ {"-o", BOR, BBINOP},
+ {"(", LPAREN, PAREN},
+ {")", RPAREN, PAREN},
+ {0, 0, 0}
+};
+
+static char **t_wp;
+static struct t_op const *t_wp_op;
+
+static void syntax(const char *, const char *);
+static int oexpr(enum token);
+static int aexpr(enum token);
+static int nexpr(enum token);
+static int primary(enum token);
+static int binop(void);
+static int filstat(char *, enum token);
+static enum token t_lex(char **);
+static int isoperand(char **);
+static int newerf(const char *, const char *);
+static int olderf(const char *, const char *);
+static int equalf(const char *, const char *);
+#ifdef HAVE_FACCESSAT
+static int test_file_access(const char *, int);
+#else
+static int test_st_mode(const struct stat64 *, int);
+static int bash_group_member(gid_t);
+#endif
+
+static inline intmax_t getn(const char *s)
+{
+ return atomax10(s);
+}
+
+static const struct t_op *getop(const char *s)
+{
+ const struct t_op *op;
+
+ for (op = ops; op->op_text; op++) {
+ if (strcmp(s, op->op_text) == 0)
+ return op;
+ }
+
+ return NULL;
+}
+
+int
+testcmd(int argc, char **argv)
+{
+ const struct t_op *op;
+ enum token n;
+ int res;
+
+ if (*argv[0] == '[') {
+ if (*argv[--argc] != ']')
+ error("missing ]");
+ argv[argc] = NULL;
+ }
+
+ argv++;
+ argc--;
+
+ if (argc < 1)
+ return 1;
+
+ /*
+ * POSIX prescriptions: he who wrote this deserves the Nobel
+ * peace prize.
+ */
+ switch (argc) {
+ case 3:
+ op = getop(argv[1]);
+ if (op && op->op_type == BINOP) {
+ n = OPERAND;
+ goto eval;
+ }
+ /* fall through */
+
+ case 4:
+ if (!strcmp(argv[0], "(") && !strcmp(argv[argc - 1], ")")) {
+ argv[--argc] = NULL;
+ argv++;
+ argc--;
+ }
+ }
+
+ n = t_lex(argv);
+
+eval:
+ t_wp = argv;
+ res = !oexpr(n);
+ argv = t_wp;
+
+ if (argv[0] != NULL && argv[1] != NULL)
+ syntax(argv[0], "unexpected operator");
+
+ return res;
+}
+
+static void
+syntax(const char *op, const char *msg)
+{
+ if (op && *op)
+ error("%s: %s", op, msg);
+ else
+ error("%s", msg);
+}
+
+static int
+oexpr(enum token n)
+{
+ int res = 0;
+
+ for (;;) {
+ res |= aexpr(n);
+ n = t_lex(t_wp + 1);
+ if (n != BOR)
+ break;
+ n = t_lex(t_wp += 2);
+ }
+ return res;
+}
+
+static int
+aexpr(enum token n)
+{
+ int res = 1;
+
+ for (;;) {
+ if (!nexpr(n))
+ res = 0;
+ n = t_lex(t_wp + 1);
+ if (n != BAND)
+ break;
+ n = t_lex(t_wp += 2);
+ }
+ return res;
+}
+
+static int
+nexpr(enum token n)
+{
+ if (n == UNOT)
+ return !nexpr(t_lex(++t_wp));
+ return primary(n);
+}
+
+static int
+primary(enum token n)
+{
+ enum token nn;
+ int res;
+
+ if (n == EOI)
+ return 0; /* missing expression */
+ if (n == LPAREN) {
+ if ((nn = t_lex(++t_wp)) == RPAREN)
+ return 0; /* missing expression */
+ res = oexpr(nn);
+ if (t_lex(++t_wp) != RPAREN)
+ syntax(NULL, "closing paren expected");
+ return res;
+ }
+ if (t_wp_op && t_wp_op->op_type == UNOP) {
+ /* unary expression */
+ if (*++t_wp == NULL)
+ syntax(t_wp_op->op_text, "argument expected");
+ switch (n) {
+ case STREZ:
+ return strlen(*t_wp) == 0;
+ case STRNZ:
+ return strlen(*t_wp) != 0;
+ case FILTT:
+ return isatty(getn(*t_wp));
+#ifdef HAVE_FACCESSAT
+ case FILRD:
+ return test_file_access(*t_wp, R_OK);
+ case FILWR:
+ return test_file_access(*t_wp, W_OK);
+ case FILEX:
+ return test_file_access(*t_wp, X_OK);
+#endif
+ default:
+ return filstat(*t_wp, n);
+ }
+ }
+
+ if (t_lex(t_wp + 1), t_wp_op && t_wp_op->op_type == BINOP) {
+ return binop();
+ }
+
+ return strlen(*t_wp) > 0;
+}
+
+static int
+binop(void)
+{
+ const char *opnd1, *opnd2;
+ struct t_op const *op;
+
+ opnd1 = *t_wp;
+ (void) t_lex(++t_wp);
+ op = t_wp_op;
+
+ if ((opnd2 = *++t_wp) == (char *)0)
+ syntax(op->op_text, "argument expected");
+
+ switch (op->op_num) {
+ default:
+#ifdef DEBUG
+ abort();
+ /* NOTREACHED */
+#endif
+ case STREQ:
+ return strcmp(opnd1, opnd2) == 0;
+ case STRNE:
+ return strcmp(opnd1, opnd2) != 0;
+ case STRLT:
+ return strcmp(opnd1, opnd2) < 0;
+ case STRGT:
+ return strcmp(opnd1, opnd2) > 0;
+ case INTEQ:
+ return getn(opnd1) == getn(opnd2);
+ case INTNE:
+ return getn(opnd1) != getn(opnd2);
+ case INTGE:
+ return getn(opnd1) >= getn(opnd2);
+ case INTGT:
+ return getn(opnd1) > getn(opnd2);
+ case INTLE:
+ return getn(opnd1) <= getn(opnd2);
+ case INTLT:
+ return getn(opnd1) < getn(opnd2);
+ case FILNT:
+ return newerf (opnd1, opnd2);
+ case FILOT:
+ return olderf (opnd1, opnd2);
+ case FILEQ:
+ return equalf (opnd1, opnd2);
+ }
+}
+
+static int
+filstat(char *nm, enum token mode)
+{
+ struct stat64 s;
+
+ if (mode == FILSYM ? lstat64(nm, &s) : stat64(nm, &s))
+ return 0;
+
+ switch (mode) {
+#ifndef HAVE_FACCESSAT
+ case FILRD:
+ return test_st_mode(&s, R_OK);
+ case FILWR:
+ return test_st_mode(&s, W_OK);
+ case FILEX:
+ return test_st_mode(&s, X_OK);
+#endif
+ case FILEXIST:
+ return 1;
+ case FILREG:
+ return S_ISREG(s.st_mode);
+ case FILDIR:
+ return S_ISDIR(s.st_mode);
+ case FILCDEV:
+ return S_ISCHR(s.st_mode);
+ case FILBDEV:
+ return S_ISBLK(s.st_mode);
+ case FILFIFO:
+ return S_ISFIFO(s.st_mode);
+ case FILSOCK:
+ return S_ISSOCK(s.st_mode);
+ case FILSYM:
+ return S_ISLNK(s.st_mode);
+ case FILSUID:
+ return (s.st_mode & S_ISUID) != 0;
+ case FILSGID:
+ return (s.st_mode & S_ISGID) != 0;
+ case FILSTCK:
+ return (s.st_mode & S_ISVTX) != 0;
+ case FILGZ:
+ return !!s.st_size;
+ case FILUID:
+ return s.st_uid == geteuid();
+ case FILGID:
+ return s.st_gid == getegid();
+ default:
+ return 1;
+ }
+}
+
+static enum token t_lex(char **tp)
+{
+ struct t_op const *op;
+ char *s = *tp;
+
+ if (s == 0) {
+ t_wp_op = (struct t_op *)0;
+ return EOI;
+ }
+
+ op = getop(s);
+ if (op && !(op->op_type == UNOP && isoperand(tp)) &&
+ !(op->op_num == LPAREN && !tp[1])) {
+ t_wp_op = op;
+ return op->op_num;
+ }
+
+ t_wp_op = (struct t_op *)0;
+ return OPERAND;
+}
+
+static int isoperand(char **tp)
+{
+ struct t_op const *op;
+ char *s;
+
+ if (!(s = tp[1]))
+ return 1;
+ if (!tp[2])
+ return 0;
+
+ op = getop(s);
+ return op && op->op_type == BINOP;
+}
+
+static int
+newerf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat (f1, &b1) == 0 &&
+ stat (f2, &b2) == 0 &&
+ b1.st_mtime > b2.st_mtime);
+}
+
+static int
+olderf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat (f1, &b1) == 0 &&
+ stat (f2, &b2) == 0 &&
+ b1.st_mtime < b2.st_mtime);
+}
+
+static int
+equalf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat (f1, &b1) == 0 &&
+ stat (f2, &b2) == 0 &&
+ b1.st_dev == b2.st_dev &&
+ b1.st_ino == b2.st_ino);
+}
+
+#ifdef HAVE_FACCESSAT
+static int test_file_access(const char *path, int mode)
+{
+ return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
+}
+#else /* HAVE_FACCESSAT */
+/*
+ * Similar to what access(2) does, but uses the effective uid and gid.
+ * Doesn't make the mistake of telling root that any file is executable.
+ * Returns non-zero if the file is accessible.
+ */
+static int
+test_st_mode(const struct stat64 *st, int mode)
+{
+ int euid = geteuid();
+
+ if (euid == 0) {
+ /* Root can read or write any file. */
+ if (mode != X_OK)
+ return 1;
+
+ /* Root can execute any file that has any one of the execute
+ bits set. */
+ mode = S_IXUSR | S_IXGRP | S_IXOTH;
+ } else if (st->st_uid == euid)
+ mode <<= 6;
+ else if (bash_group_member(st->st_gid))
+ mode <<= 3;
+
+ return st->st_mode & mode;
+}
+
+/* Return non-zero if GID is one that we have in our groups list. */
+static int
+bash_group_member(gid_t gid)
+{
+ register int i;
+ gid_t *group_array;
+ int ngroups;
+
+ /* Short-circuit if possible, maybe saving a call to getgroups(). */
+ if (gid == getgid() || gid == getegid())
+ return (1);
+
+ ngroups = getgroups(0, NULL);
+ group_array = stalloc(ngroups * sizeof(gid_t));
+ if ((getgroups(ngroups, group_array)) != ngroups)
+ return (0);
+
+ /* Search through the list looking for GID. */
+ for (i = 0; i < ngroups; i++)
+ if (gid == group_array[i])
+ return (1);
+
+ return (0);
+}
+#endif /* HAVE_FACCESSAT */
diff --git a/usr/dash/builtins.def.in b/usr/dash/builtins.def.in
new file mode 100644
index 0000000..e116963
--- /dev/null
+++ b/usr/dash/builtins.def.in
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)builtins.def 8.4 (Berkeley) 5/4/95
+ */
+
+/*
+ * This file lists all the builtin commands. The first column is the name
+ * of a C routine.
+ * The -a flag specifies that this is a posix 'assignment builtin' command.
+ * The -s flag specifies that this is a posix 'special builtin' command.
+ * The -u flag specifies that this is a posix 'standard utility'.
+ * The -n flag specifies that this command has a special entry point.
+ * The rest of the line specifies the command name or names used to run
+ * the command.
+ */
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+
+#if JOBS
+bgcmd -u bg
+fgcmd -u fg
+#endif
+
+#ifndef SMALL
+histcmd -u fc
+#endif
+
+breakcmd -s break -s continue
+cdcmd -u cd chdir
+commandcmd -u command
+dotcmd -s .
+echocmd echo
+evalcmd -ns eval
+execcmd -s exec
+exitcmd -s exit
+exportcmd -as export -as readonly
+falsecmd -u false
+getoptscmd -u getopts
+hashcmd hash
+jobscmd -u jobs
+localcmd -as local
+printfcmd printf
+pwdcmd pwd
+readcmd -u read
+returncmd -s return
+setcmd -s set
+shiftcmd -s shift
+trapcmd -s trap
+truecmd -s : -u true
+typecmd type
+umaskcmd -u umask
+unaliascmd -u unalias
+unsetcmd -s unset
+waitcmd -u wait
+aliascmd -au alias
+#ifdef HAVE_GETRLIMIT
+ulimitcmd ulimit
+#endif
+testcmd test [
+killcmd -u kill
diff --git a/usr/dash/cd.c b/usr/dash/cd.c
new file mode 100644
index 0000000..89c6c30
--- /dev/null
+++ b/usr/dash/cd.c
@@ -0,0 +1,313 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE 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/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+/*
+ * The cd and pwd commands.
+ */
+
+#include "shell.h"
+#include "var.h"
+#include "nodes.h" /* for jobs.h */
+#include "jobs.h"
+#include "options.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "exec.h"
+#include "redir.h"
+#include "main.h"
+#include "mystring.h"
+#include "show.h"
+#include "cd.h"
+
+#define CD_PHYSICAL 1
+#define CD_PRINT 2
+
+STATIC int docd(const char *, int);
+STATIC const char *updatepwd(const char *);
+STATIC char *getpwd(void);
+STATIC int cdopt(void);
+
+STATIC char *curdir = nullstr; /* current working directory */
+STATIC char *physdir = nullstr; /* physical working directory */
+
+STATIC int
+cdopt()
+{
+ int flags = 0;
+ int i, j;
+
+ j = 'L';
+ while ((i = nextopt("LP"))) {
+ if (i != j) {
+ flags ^= CD_PHYSICAL;
+ j = i;
+ }
+ }
+
+ return flags;
+}
+
+int
+cdcmd(int argc, char **argv)
+{
+ const char *dest;
+ const char *path;
+ const char *p;
+ char c;
+ struct stat statb;
+ int flags;
+
+ flags = cdopt();
+ dest = *argptr;
+ if (!dest)
+ dest = bltinlookup(homestr);
+ else if (dest[0] == '-' && dest[1] == '\0') {
+ dest = bltinlookup("OLDPWD");
+ flags |= CD_PRINT;
+ }
+ if (!dest)
+ dest = nullstr;
+ if (*dest == '/')
+ goto step6;
+ if (*dest == '.') {
+ c = dest[1];
+dotdot:
+ switch (c) {
+ case '\0':
+ case '/':
+ goto step6;
+ case '.':
+ c = dest[2];
+ if (c != '.')
+ goto dotdot;
+ }
+ }
+ if (!*dest)
+ dest = ".";
+ path = bltinlookup("CDPATH");
+ while (path) {
+ c = *path;
+ p = padvance(&path, dest);
+ if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
+ if (c && c != ':')
+ flags |= CD_PRINT;
+docd:
+ if (!docd(p, flags))
+ goto out;
+ goto err;
+ }
+ }
+
+step6:
+ p = dest;
+ goto docd;
+
+err:
+ sh_error("can't cd to %s", dest);
+ /* NOTREACHED */
+out:
+ if (flags & CD_PRINT)
+ out1fmt(snlfmt, curdir);
+ return 0;
+}
+
+
+/*
+ * Actually do the chdir. We also call hashcd to let the routines in exec.c
+ * know that the current directory has changed.
+ */
+
+STATIC int
+docd(const char *dest, int flags)
+{
+ const char *dir = 0;
+ int err;
+
+ TRACE(("docd(\"%s\", %d) called\n", dest, flags));
+
+ INTOFF;
+ if (!(flags & CD_PHYSICAL)) {
+ dir = updatepwd(dest);
+ if (dir)
+ dest = dir;
+ }
+ err = chdir(dest);
+ if (err)
+ goto out;
+ setpwd(dir, 1);
+ hashcd();
+out:
+ INTON;
+ return err;
+}
+
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command.
+ */
+
+STATIC const char *
+updatepwd(const char *dir)
+{
+ char *new;
+ char *p;
+ char *cdcomppath;
+ const char *lim;
+
+ cdcomppath = sstrdup(dir);
+ STARTSTACKSTR(new);
+ if (*dir != '/') {
+ if (curdir == nullstr)
+ return 0;
+ new = stputs(curdir, new);
+ }
+ new = makestrspace(strlen(dir) + 2, new);
+ lim = stackblock() + 1;
+ if (*dir != '/') {
+ if (new[-1] != '/')
+ USTPUTC('/', new);
+ if (new > lim && *lim == '/')
+ lim++;
+ } else {
+ USTPUTC('/', new);
+ cdcomppath++;
+ if (dir[1] == '/' && dir[2] != '/') {
+ USTPUTC('/', new);
+ cdcomppath++;
+ lim++;
+ }
+ }
+ p = strtok(cdcomppath, "/");
+ while (p) {
+ switch(*p) {
+ case '.':
+ if (p[1] == '.' && p[2] == '\0') {
+ while (new > lim) {
+ STUNPUTC(new);
+ if (new[-1] == '/')
+ break;
+ }
+ break;
+ } else if (p[1] == '\0')
+ break;
+ /* fall through */
+ default:
+ new = stputs(p, new);
+ USTPUTC('/', new);
+ }
+ p = strtok(0, "/");
+ }
+ if (new > lim)
+ STUNPUTC(new);
+ *new = 0;
+ return stackblock();
+}
+
+
+/*
+ * Find out what the current directory is. If we already know the current
+ * directory, this routine returns immediately.
+ */
+inline
+STATIC char *
+getpwd()
+{
+#ifdef __GLIBC__
+ char *dir = getcwd(0, 0);
+ if (dir)
+ return dir;
+#else
+ char buf[PATH_MAX];
+ if(getcwd(buf, sizeof(buf)))
+ return savestr(buf);
+#endif
+ sh_warnx("getcwd() failed: %s", strerror(errno));
+ return nullstr;
+}
+
+int
+pwdcmd(int argc, char **argv)
+{
+ int flags;
+ const char *dir = curdir;
+
+ flags = cdopt();
+ if (flags) {
+ if (physdir == nullstr)
+ setpwd(dir, 0);
+ dir = physdir;
+ }
+ out1fmt(snlfmt, dir);
+ return 0;
+}
+
+void
+setpwd(const char *val, int setold)
+{
+ char *oldcur, *dir;
+
+ oldcur = dir = curdir;
+
+ if (setold) {
+ setvar("OLDPWD", oldcur, VEXPORT);
+ }
+ INTOFF;
+ if (physdir != nullstr) {
+ if (physdir != oldcur)
+ free(physdir);
+ physdir = nullstr;
+ }
+ if (oldcur == val || !val) {
+ char *s = getpwd();
+ physdir = s;
+ if (!val)
+ dir = s;
+ } else
+ dir = savestr(val);
+ if (oldcur != dir && oldcur != nullstr) {
+ free(oldcur);
+ }
+ curdir = dir;
+ INTON;
+ setvar("PWD", dir, VEXPORT);
+}
diff --git a/usr/dash/cd.h b/usr/dash/cd.h
new file mode 100644
index 0000000..8763161
--- /dev/null
+++ b/usr/dash/cd.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+int cdcmd(int, char **);
+int pwdcmd(int, char **);
+void setpwd(const char *, int);
diff --git a/usr/dash/config.h b/usr/dash/config.h
new file mode 100644
index 0000000..9757009
--- /dev/null
+++ b/usr/dash/config.h
@@ -0,0 +1,191 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if __attribute__((__alias__())) is supported */
+#define HAVE_ALIAS_ATTRIBUTE 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the `bsearch' function. */
+#define HAVE_BSEARCH 1
+
+/* Define to 1 if you have the declaration of `isblank', and to 0 if you
+ don't. */
+#define HAVE_DECL_ISBLANK 1
+
+/* Define to 1 if you have the `faccessat' function. */
+/* #undef HAVE_FACCESSAT */
+
+/* Define to 1 if you have the `fnmatch' function. */
+/* #undef HAVE_FNMATCH */
+
+/* Define to 1 if you have the `getpwnam' function. */
+#define HAVE_GETPWNAM 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+/* #undef HAVE_GETRLIMIT */
+
+/* Define to 1 if you have the `glob' function. */
+/* #undef HAVE_GLOB */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `isalpha' function. */
+#define HAVE_ISALPHA 1
+
+/* Define to 1 if you have the `killpg' function. */
+/* #undef HAVE_KILLPG */
+
+/* Define to 1 if you have the <memory.h> header file. */
+/* #undef HAVE_MEMORY_H */
+
+/* Define to 1 if you have the `mempcpy' function. */
+/* #undef HAVE_MEMPCPY */
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Define to 1 if you have the `sigsetmask' function. */
+/* #undef HAVE_SIGSETMASK */
+
+/* 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 `stpcpy' function. */
+/* #undef HAVE_STPCPY */
+
+/* Define to 1 if you have the `strchrnul' function. */
+/* #undef HAVE_STRCHRNUL */
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #undef HAVE_STRINGS_H */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strsignal' function. */
+#define HAVE_STRSIGNAL 1
+
+/* Define to 1 if you have the `strtod' function. */
+/* #undef HAVE_STRTOD */
+
+/* Define to 1 if you have the `strtoimax' function. */
+#define HAVE_STRTOIMAX 1
+
+/* Define to 1 if you have the `strtoumax' function. */
+#define HAVE_STRTOUMAX 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 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
+
+/* Name of package */
+#define PACKAGE "dash"
+
+/* 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 "dash"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "dash 0.5.7"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "dash"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.5.7"
+
+/* Define to printf format string for intmax_t */
+/* #undef PRIdMAX */
+
+/* The size of `intmax_t', as computed by sizeof. */
+#define SIZEOF_INTMAX_T 8
+
+/* The size of `long long int', as computed by sizeof. */
+#define SIZEOF_LONG_LONG_INT 8
+
+/* Define if you build with -DSMALL */
+#define SMALL 1
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Version number of package */
+#define VERSION "0.5.7"
+
+/* Define if you build with -DWITH_LINENO */
+#define WITH_LINENO 1
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to system shell path */
+/* #undef _PATH_BSHELL */
+
+/* Define to devnull device node path */
+/* #undef _PATH_DEVNULL */
+
+/* Define to tty device node path */
+/* #undef _PATH_TTY */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* 64-bit operations are the same as 32-bit */
+#define fstat64 fstat
+
+/* 64-bit operations are the same as 32-bit */
+#define lstat64 lstat
+
+/* 64-bit operations are the same as 32-bit */
+#define open64 open
+
+/* klibc has bsd_signal instead of signal */
+/* #undef signal */
+
+/* 64-bit operations are the same as 32-bit */
+#define stat64 stat
diff --git a/usr/dash/error.c b/usr/dash/error.c
new file mode 100644
index 0000000..9d31989
--- /dev/null
+++ b/usr/dash/error.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Errors and exceptions.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "shell.h"
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "show.h"
+#include "eval.h"
+#include "parser.h"
+#include "system.h"
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+int exception;
+int suppressint;
+volatile sig_atomic_t intpending;
+int errlinno;
+
+
+static void exverror(int, const char *, va_list)
+ __attribute__((__noreturn__));
+
+/*
+ * Called to raise an exception. Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler. The type of exception is
+ * stored in the global variable "exception".
+ */
+
+void
+exraise(int e)
+{
+#ifdef DEBUG
+ if (handler == NULL)
+ abort();
+#endif
+ INTOFF;
+
+ exception = e;
+ longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received. (If the user specifies
+ * that SIGINT is to be trapped or ignored using the trap builtin, then
+ * this routine is not called.) Suppressint is nonzero when interrupts
+ * are held using the INTOFF macro. (The test for iflag is just
+ * defensive programming.)
+ */
+
+void
+onint(void) {
+
+ intpending = 0;
+ sigclearmask();
+ if (!(rootshell && iflag)) {
+ signal(SIGINT, SIG_DFL);
+ raise(SIGINT);
+ }
+ exraise(EXINT);
+ /* NOTREACHED */
+}
+
+static void
+exvwarning2(const char *msg, va_list ap)
+{
+ struct output *errs;
+ const char *name;
+ const char *fmt;
+
+ errs = out2;
+ name = arg0 ? arg0 : "sh";
+ if (!commandname)
+ fmt = "%s: %d: ";
+ else
+ fmt = "%s: %d: %s: ";
+ outfmt(errs, fmt, name, errlinno, commandname);
+ doformat(errs, msg, ap);
+#if FLUSHERR
+ outc('\n', errs);
+#else
+ outcslow('\n', errs);
+#endif
+}
+
+#define exvwarning(a, b, c) exvwarning2(b, c)
+
+/*
+ * Exverror is called to raise the error exception. If the second argument
+ * is not NULL then error prints an error message using printf style
+ * formatting. It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+#ifdef DEBUG
+ if (msg) {
+ va_list aq;
+ TRACE(("exverror(%d, \"", cond));
+ va_copy(aq, ap);
+ TRACEV((msg, aq));
+ va_end(aq);
+ TRACE(("\") pid=%d\n", getpid()));
+ } else
+ TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+ if (msg)
+#endif
+ exvwarning(-1, msg, ap);
+
+ flushall();
+ exraise(cond);
+ /* NOTREACHED */
+}
+
+
+void
+sh_error(const char *msg, ...)
+{
+ va_list ap;
+
+ exitstatus = 2;
+
+ va_start(ap, msg);
+ exverror(EXERROR, msg, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ exverror(cond, msg, ap);
+ /* NOTREACHED */
+ va_end(ap);
+}
+
+/*
+ * error/warning routines for external builtins
+ */
+
+void
+sh_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ exvwarning(-1, fmt, ap);
+ va_end(ap);
+}
+
+
+/*
+ * Return a string describing an error. The returned string may be a
+ * pointer to a static buffer that will be overwritten on the next call.
+ * Action describes the operation that got the error.
+ */
+
+const char *
+errmsg(int e, int action)
+{
+ if (e != ENOENT && e != ENOTDIR)
+ return strerror(e);
+
+ if (action & E_OPEN)
+ return "No such file";
+ else if (action & E_CREAT)
+ return "Directory nonexistent";
+ else
+ return "not found";
+}
+
+
+#ifdef REALLY_SMALL
+void
+__inton() {
+ if (--suppressint == 0 && intpending) {
+ onint();
+ }
+}
+#endif
diff --git a/usr/dash/error.h b/usr/dash/error.h
new file mode 100644
index 0000000..f91d11d
--- /dev/null
+++ b/usr/dash/error.h
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)error.h 8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef DASH_ERROR_H
+#define DASH_ERROR_H
+
+#include <setjmp.h>
+#include <signal.h>
+
+/*
+ * Types of operations (passed to the errmsg routine).
+ */
+
+#define E_OPEN 01 /* opening a file */
+#define E_CREAT 02 /* creating a file */
+#define E_EXEC 04 /* executing a program */
+
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations. The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exeception. To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+struct jmploc {
+ jmp_buf loc;
+};
+
+extern struct jmploc *handler;
+extern int exception;
+
+/* exceptions */
+#define EXINT 0 /* SIGINT received */
+#define EXERROR 1 /* a generic error */
+#define EXEXIT 4 /* exit the shell */
+
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time. This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable. (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+extern int suppressint;
+extern volatile sig_atomic_t intpending;
+
+#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
+#define INTOFF \
+ ({ \
+ suppressint++; \
+ barrier(); \
+ 0; \
+ })
+#ifdef REALLY_SMALL
+void __inton(void);
+#define INTON __inton()
+#else
+#define INTON \
+ ({ \
+ barrier(); \
+ if (--suppressint == 0 && intpending) onint(); \
+ 0; \
+ })
+#endif
+#define FORCEINTON \
+ ({ \
+ barrier(); \
+ suppressint = 0; \
+ if (intpending) onint(); \
+ 0; \
+ })
+#define SAVEINT(v) ((v) = suppressint)
+#define RESTOREINT(v) \
+ ({ \
+ barrier(); \
+ if ((suppressint = (v)) == 0 && intpending) onint(); \
+ 0; \
+ })
+#define CLEAR_PENDING_INT intpending = 0
+#define int_pending() intpending
+
+void exraise(int) __attribute__((__noreturn__));
+#ifdef USE_NORETURN
+void onint(void) __attribute__((__noreturn__));
+#else
+void onint(void);
+#endif
+extern int errlinno;
+void sh_error(const char *, ...) __attribute__((__noreturn__));
+void exerror(int, const char *, ...) __attribute__((__noreturn__));
+const char *errmsg(int, int);
+
+void sh_warnx(const char *, ...);
+
+#endif /* DASH_ERROR_H */
diff --git a/usr/dash/eval.c b/usr/dash/eval.c
new file mode 100644
index 0000000..145e0b4
--- /dev/null
+++ b/usr/dash/eval.c
@@ -0,0 +1,1092 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/*
+ * Evaluate a command.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "syntax.h"
+#include "expand.h"
+#include "parser.h"
+#include "jobs.h"
+#include "eval.h"
+#include "builtins.h"
+#include "options.h"
+#include "exec.h"
+#include "redir.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "show.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+
+/* flags in argument to evaltree */
+#define EV_EXIT 01 /* exit after evaluating tree */
+#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+
+int evalskip; /* set if we are skipping commands */
+STATIC int skipcount; /* number of levels to skip */
+MKINIT int loopnest; /* current loop nesting level */
+static int funcline; /* starting line number of current function, or 0 if not in a function */
+
+
+char *commandname;
+int exitstatus; /* exit status of last command */
+int back_exitstatus; /* exit status of backquoted command */
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *, int) __attribute__ ((__noreturn__));
+STATIC void evalloop(union node *, int);
+STATIC void evalfor(union node *, int);
+STATIC void evalcase(union node *, int);
+STATIC void evalsubshell(union node *, int);
+STATIC void expredir(union node *);
+STATIC void evalpipe(union node *, int);
+#ifdef notyet
+STATIC void evalcommand(union node *, int, struct backcmd *);
+#else
+STATIC void evalcommand(union node *, int);
+#endif
+STATIC int evalbltin(const struct builtincmd *, int, char **, int);
+STATIC int evalfun(struct funcnode *, int, char **, int);
+STATIC void prehash(union node *);
+STATIC int eprintlist(struct output *, struct strlist *, int);
+STATIC int bltincmd(int, char **);
+
+
+STATIC const struct builtincmd bltin = {
+ .name = nullstr,
+ .builtin = bltincmd
+};
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+#ifdef mkinit
+INCLUDE "eval.h"
+
+RESET {
+ evalskip = 0;
+ loopnest = 0;
+}
+#endif
+
+
+
+/*
+ * The eval commmand.
+ */
+
+static int evalcmd(int argc, char **argv, int flags)
+{
+ char *p;
+ char *concat;
+ char **ap;
+
+ if (argc > 1) {
+ p = argv[1];
+ if (argc > 2) {
+ STARTSTACKSTR(concat);
+ ap = argv + 2;
+ for (;;) {
+ concat = stputs(p, concat);
+ if ((p = *ap++) == NULL)
+ break;
+ STPUTC(' ', concat);
+ }
+ STPUTC('\0', concat);
+ p = grabstackstr(concat);
+ }
+ return evalstring(p, flags & EV_TESTED);
+ }
+ return 0;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+int
+evalstring(char *s, int flags)
+{
+ union node *n;
+ struct stackmark smark;
+ int status;
+
+ setinputstring(s);
+ setstackmark(&smark);
+
+ status = 0;
+ while ((n = parsecmd(0)) != NEOF) {
+ evaltree(n, flags);
+ status = exitstatus;
+ popstackmark(&smark);
+ if (evalskip)
+ break;
+ }
+ popfile();
+
+ return status;
+}
+
+
+
+/*
+ * Evaluate a parse tree. The value is left in the global variable
+ * exitstatus.
+ */
+
+void
+evaltree(union node *n, int flags)
+{
+ int checkexit = 0;
+ void (*evalfn)(union node *, int);
+ unsigned isor;
+ int status;
+ if (n == NULL) {
+ TRACE(("evaltree(NULL) called\n"));
+ goto out;
+ }
+#ifndef SMALL
+ displayhist = 1; /* show history substitutions done with fc */
+#endif
+ TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
+ getpid(), n, n->type, flags));
+ switch (n->type) {
+ default:
+#ifdef DEBUG
+ out1fmt("Node type = %d\n", n->type);
+#ifndef USE_GLIBC_STDIO
+ flushout(out1);
+#endif
+ break;
+#endif
+ case NNOT:
+ evaltree(n->nnot.com, EV_TESTED);
+ status = !exitstatus;
+ goto setstatus;
+ case NREDIR:
+ errlinno = lineno = n->nredir.linno;
+ if (funcline)
+ lineno -= funcline - 1;
+ expredir(n->nredir.redirect);
+ pushredir(n->nredir.redirect);
+ status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
+ if (!status) {
+ evaltree(n->nredir.n, flags & EV_TESTED);
+ status = exitstatus;
+ }
+ if (n->nredir.redirect)
+ popredir(0);
+ goto setstatus;
+ case NCMD:
+#ifdef notyet
+ if (eflag && !(flags & EV_TESTED))
+ checkexit = ~0;
+ evalcommand(n, flags, (struct backcmd *)NULL);
+ break;
+#else
+ evalfn = evalcommand;
+checkexit:
+ if (eflag && !(flags & EV_TESTED))
+ checkexit = ~0;
+ goto calleval;
+#endif
+ case NFOR:
+ evalfn = evalfor;
+ goto calleval;
+ case NWHILE:
+ case NUNTIL:
+ evalfn = evalloop;
+ goto calleval;
+ case NSUBSHELL:
+ case NBACKGND:
+ evalfn = evalsubshell;
+ goto checkexit;
+ case NPIPE:
+ evalfn = evalpipe;
+ goto checkexit;
+ case NCASE:
+ evalfn = evalcase;
+ goto calleval;
+ case NAND:
+ case NOR:
+ case NSEMI:
+#if NAND + 1 != NOR
+#error NAND + 1 != NOR
+#endif
+#if NOR + 1 != NSEMI
+#error NOR + 1 != NSEMI
+#endif
+ isor = n->type - NAND;
+ evaltree(
+ n->nbinary.ch1,
+ (flags | ((isor >> 1) - 1)) & EV_TESTED
+ );
+ if ((!exitstatus) == isor)
+ break;
+ if (!evalskip) {
+ n = n->nbinary.ch2;
+evaln:
+ evalfn = evaltree;
+calleval:
+ evalfn(n, flags);
+ break;
+ }
+ break;
+ case NIF:
+ evaltree(n->nif.test, EV_TESTED);
+ if (evalskip)
+ break;
+ if (exitstatus == 0) {
+ n = n->nif.ifpart;
+ goto evaln;
+ } else if (n->nif.elsepart) {
+ n = n->nif.elsepart;
+ goto evaln;
+ }
+ goto success;
+ case NDEFUN:
+ defun(n);
+success:
+ status = 0;
+setstatus:
+ exitstatus = status;
+ break;
+ }
+out:
+ if (checkexit & exitstatus)
+ goto exexit;
+
+ if (pendingsigs)
+ dotrap();
+
+ if (flags & EV_EXIT) {
+exexit:
+ exraise(EXEXIT);
+ }
+}
+
+
+#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
+STATIC
+#endif
+void evaltreenr(union node *n, int flags)
+#ifdef HAVE_ATTRIBUTE_ALIAS
+ __attribute__ ((alias("evaltree")));
+#else
+{
+ evaltree(n, flags);
+ abort();
+}
+#endif
+
+
+STATIC void
+evalloop(union node *n, int flags)
+{
+ int status;
+
+ loopnest++;
+ status = 0;
+ flags &= EV_TESTED;
+ for (;;) {
+ int i;
+
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip) {
+skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ break;
+ }
+ i = exitstatus;
+ if (n->type != NWHILE)
+ i = !i;
+ if (i != 0)
+ break;
+ evaltree(n->nbinary.ch2, flags);
+ status = exitstatus;
+ if (evalskip)
+ goto skipping;
+ }
+ loopnest--;
+ exitstatus = status;
+}
+
+
+
+STATIC void
+evalfor(union node *n, int flags)
+{
+ struct arglist arglist;
+ union node *argp;
+ struct strlist *sp;
+ struct stackmark smark;
+
+ errlinno = lineno = n->nfor.linno;
+ if (funcline)
+ lineno -= funcline - 1;
+
+ setstackmark(&smark);
+ arglist.lastp = &arglist.list;
+ for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ /* XXX */
+ if (evalskip)
+ goto out;
+ }
+ *arglist.lastp = NULL;
+
+ exitstatus = 0;
+ loopnest++;
+ flags &= EV_TESTED;
+ for (sp = arglist.list ; sp ; sp = sp->next) {
+ setvar(n->nfor.var, sp->text, 0);
+ evaltree(n->nfor.body, flags);
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ break;
+ }
+ }
+ loopnest--;
+out:
+ popstackmark(&smark);
+}
+
+
+
+STATIC void
+evalcase(union node *n, int flags)
+{
+ union node *cp;
+ union node *patp;
+ struct arglist arglist;
+ struct stackmark smark;
+
+ errlinno = lineno = n->ncase.linno;
+ if (funcline)
+ lineno -= funcline - 1;
+
+ setstackmark(&smark);
+ arglist.lastp = &arglist.list;
+ expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+ exitstatus = 0;
+ for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
+ for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+ if (casematch(patp, arglist.list->text)) {
+ if (evalskip == 0) {
+ evaltree(cp->nclist.body, flags);
+ }
+ goto out;
+ }
+ }
+ }
+out:
+ popstackmark(&smark);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+STATIC void
+evalsubshell(union node *n, int flags)
+{
+ struct job *jp;
+ int backgnd = (n->type == NBACKGND);
+ int status;
+
+ errlinno = lineno = n->nredir.linno;
+ if (funcline)
+ lineno -= funcline - 1;
+
+ expredir(n->nredir.redirect);
+ if (!backgnd && flags & EV_EXIT && !have_traps())
+ goto nofork;
+ INTOFF;
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, backgnd) == 0) {
+ INTON;
+ flags |= EV_EXIT;
+ if (backgnd)
+ flags &=~ EV_TESTED;
+nofork:
+ redirect(n->nredir.redirect, 0);
+ evaltreenr(n->nredir.n, flags);
+ /* never returns */
+ }
+ status = 0;
+ if (! backgnd)
+ status = waitforjob(jp);
+ exitstatus = status;
+ INTON;
+}
+
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+STATIC void
+expredir(union node *n)
+{
+ union node *redir;
+
+ for (redir = n ; redir ; redir = redir->nfile.next) {
+ struct arglist fn;
+ fn.lastp = &fn.list;
+ switch (redir->type) {
+ case NFROMTO:
+ case NFROM:
+ case NTO:
+ case NCLOBBER:
+ case NAPPEND:
+ expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+ redir->nfile.expfname = fn.list->text;
+ break;
+ case NFROMFD:
+ case NTOFD:
+ if (redir->ndup.vname) {
+ expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
+ fixredir(redir, fn.list->text, 1);
+ }
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Evaluate a pipeline. All the processes in the pipeline are children
+ * of the process creating the pipeline. (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+STATIC void
+evalpipe(union node *n, int flags)
+{
+ struct job *jp;
+ struct nodelist *lp;
+ int pipelen;
+ int prevfd;
+ int pip[2];
+
+ TRACE(("evalpipe(0x%lx) called\n", (long)n));
+ pipelen = 0;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+ pipelen++;
+ flags |= EV_EXIT;
+ INTOFF;
+ jp = makejob(n, pipelen);
+ prevfd = -1;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ prehash(lp->n);
+ pip[1] = -1;
+ if (lp->next) {
+ if (pipe(pip) < 0) {
+ close(prevfd);
+ sh_error("Pipe call failed");
+ }
+ }
+ if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+ INTON;
+ if (pip[1] >= 0) {
+ close(pip[0]);
+ }
+ if (prevfd > 0) {
+ dup2(prevfd, 0);
+ close(prevfd);
+ }
+ if (pip[1] > 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ evaltreenr(lp->n, flags);
+ /* never returns */
+ }
+ if (prevfd >= 0)
+ close(prevfd);
+ prevfd = pip[0];
+ close(pip[1]);
+ }
+ if (n->npipe.backgnd == 0) {
+ exitstatus = waitforjob(jp);
+ TRACE(("evalpipe: job done exit status %d\n", exitstatus));
+ }
+ INTON;
+}
+
+
+
+/*
+ * Execute a command inside back quotes. If it's a builtin command, we
+ * want to save its output in a block obtained from malloc. Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+ int pip[2];
+ struct job *jp;
+
+ result->fd = -1;
+ result->buf = NULL;
+ result->nleft = 0;
+ result->jp = NULL;
+ if (n == NULL) {
+ goto out;
+ }
+
+ if (pipe(pip) < 0)
+ sh_error("Pipe call failed");
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ ifsfree();
+ evaltreenr(n, EV_EXIT);
+ /* NOTREACHED */
+ }
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
+
+out:
+ TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
+ result->fd, result->buf, result->nleft, result->jp));
+}
+
+static char **
+parse_command_args(char **argv, const char **path)
+{
+ char *cp, c;
+
+ for (;;) {
+ cp = *++argv;
+ if (!cp)
+ return 0;
+ if (*cp++ != '-')
+ break;
+ if (!(c = *cp++))
+ break;
+ if (c == '-' && !*cp) {
+ if (!*++argv)
+ return 0;
+ break;
+ }
+ do {
+ switch (c) {
+ case 'p':
+ *path = defpath;
+ break;
+ default:
+ /* run 'typecmd' for other options */
+ return 0;
+ }
+ } while ((c = *cp++));
+ }
+ return argv;
+}
+
+
+
+/*
+ * Execute a simple command.
+ */
+
+STATIC void
+#ifdef notyet
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+#else
+evalcommand(union node *cmd, int flags)
+#endif
+{
+ struct localvar_list *localvar_stop;
+ struct redirtab *redir_stop;
+ struct stackmark smark;
+ union node *argp;
+ struct arglist arglist;
+ struct arglist varlist;
+ char **argv;
+ int argc;
+ struct strlist *sp;
+#ifdef notyet
+ int pip[2];
+#endif
+ struct cmdentry cmdentry;
+ struct job *jp;
+ char *lastarg;
+ const char *path;
+ int spclbltin;
+ int execcmd;
+ int status;
+ char **nargv;
+
+ errlinno = lineno = cmd->ncmd.linno;
+ if (funcline)
+ lineno -= funcline - 1;
+
+ /* First expand the arguments. */
+ TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
+ setstackmark(&smark);
+ localvar_stop = pushlocalvars();
+ back_exitstatus = 0;
+
+ cmdentry.cmdtype = CMDBUILTIN;
+ cmdentry.u.cmd = &bltin;
+ varlist.lastp = &varlist.list;
+ *varlist.lastp = NULL;
+ arglist.lastp = &arglist.list;
+ *arglist.lastp = NULL;
+
+ argc = 0;
+ for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
+ struct strlist **spp;
+
+ spp = arglist.lastp;
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ for (sp = *spp; sp; sp = sp->next)
+ argc++;
+ }
+
+ /* Reserve one extra spot at the front for shellexec. */
+ nargv = stalloc(sizeof (char *) * (argc + 2));
+ argv = ++nargv;
+ for (sp = arglist.list ; sp ; sp = sp->next) {
+ TRACE(("evalcommand arg: %s\n", sp->text));
+ *nargv++ = sp->text;
+ }
+ *nargv = NULL;
+
+ lastarg = NULL;
+ if (iflag && funcline == 0 && argc > 0)
+ lastarg = nargv[-1];
+
+ preverrout.fd = 2;
+ expredir(cmd->ncmd.redirect);
+ redir_stop = pushredir(cmd->ncmd.redirect);
+ status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
+
+ path = vpath.text;
+ for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
+ struct strlist **spp;
+ char *p;
+
+ spp = varlist.lastp;
+ expandarg(argp, &varlist, EXP_VARTILDE);
+
+ mklocal((*spp)->text);
+
+ /*
+ * Modify the command lookup path, if a PATH= assignment
+ * is present
+ */
+ p = (*spp)->text;
+ if (varequal(p, path))
+ path = p;
+ }
+
+ /* Print the command if xflag is set. */
+ if (xflag) {
+ struct output *out;
+ int sep;
+
+ out = &preverrout;
+ outstr(expandstr(ps4val()), out);
+ sep = 0;
+ sep = eprintlist(out, varlist.list, sep);
+ eprintlist(out, arglist.list, sep);
+ outcslow('\n', out);
+#ifdef FLUSHERR
+ flushout(out);
+#endif
+ }
+
+ execcmd = 0;
+ spclbltin = -1;
+
+ /* Now locate the command. */
+ if (argc) {
+ const char *oldpath;
+ int cmd_flag = DO_ERR;
+
+ path += 5;
+ oldpath = path;
+ for (;;) {
+ find_command(argv[0], &cmdentry, cmd_flag, path);
+ if (cmdentry.cmdtype == CMDUNKNOWN) {
+ status = 127;
+#ifdef FLUSHERR
+ flushout(&errout);
+#endif
+ goto bail;
+ }
+
+ /* implement bltin and command here */
+ if (cmdentry.cmdtype != CMDBUILTIN)
+ break;
+ if (spclbltin < 0)
+ spclbltin =
+ cmdentry.u.cmd->flags &
+ BUILTIN_SPECIAL
+ ;
+ if (cmdentry.u.cmd == EXECCMD)
+ execcmd++;
+ if (cmdentry.u.cmd != COMMANDCMD)
+ break;
+
+ path = oldpath;
+ nargv = parse_command_args(argv, &path);
+ if (!nargv)
+ break;
+ argc -= nargv - argv;
+ argv = nargv;
+ cmd_flag |= DO_NOFUNC;
+ }
+ }
+
+ if (status) {
+bail:
+ exitstatus = status;
+
+ /* We have a redirection error. */
+ if (spclbltin > 0)
+ exraise(EXERROR);
+
+ goto out;
+ }
+
+ /* Execute the command. */
+ switch (cmdentry.cmdtype) {
+ default:
+ /* Fork off a child process if necessary. */
+ if (!(flags & EV_EXIT) || have_traps()) {
+ INTOFF;
+ jp = makejob(cmd, 1);
+ if (forkshell(jp, cmd, FORK_FG) != 0) {
+ exitstatus = waitforjob(jp);
+ INTON;
+ break;
+ }
+ FORCEINTON;
+ }
+ listsetvar(varlist.list, VEXPORT|VSTACK);
+ shellexec(argv, path, cmdentry.u.index);
+ /* NOTREACHED */
+
+ case CMDBUILTIN:
+ if (spclbltin > 0 || argc == 0) {
+ poplocalvars(1);
+ if (execcmd && argc > 1)
+ listsetvar(varlist.list, VEXPORT);
+ }
+ if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
+ int status;
+ int i;
+
+ i = exception;
+ if (i == EXEXIT)
+ goto raise;
+
+ status = (i == EXINT) ? SIGINT + 128 : 2;
+ exitstatus = status;
+
+ if (i == EXINT || spclbltin > 0) {
+raise:
+ longjmp(handler->loc, 1);
+ }
+ FORCEINTON;
+ }
+ break;
+
+ case CMDFUNCTION:
+ poplocalvars(1);
+ if (evalfun(cmdentry.u.func, argc, argv, flags))
+ goto raise;
+ break;
+ }
+
+out:
+ if (cmd->ncmd.redirect)
+ popredir(execcmd);
+ unwindredir(redir_stop);
+ unwindlocalvars(localvar_stop);
+ if (lastarg)
+ /* dsl: I think this is intended to be used to support
+ * '_' in 'vi' command mode during line editing...
+ * However I implemented that within libedit itself.
+ */
+ setvar("_", lastarg, 0);
+ popstackmark(&smark);
+}
+
+STATIC int
+evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
+{
+ char *volatile savecmdname;
+ struct jmploc *volatile savehandler;
+ struct jmploc jmploc;
+ int status;
+ int i;
+
+ savecmdname = commandname;
+ savehandler = handler;
+ if ((i = setjmp(jmploc.loc)))
+ goto cmddone;
+ handler = &jmploc;
+ commandname = argv[0];
+ argptr = argv + 1;
+ optptr = NULL; /* initialize nextopt */
+ if (cmd == EVALCMD)
+ status = evalcmd(argc, argv, flags);
+ else
+ status = (*cmd->builtin)(argc, argv);
+ flushall();
+ status |= outerr(out1);
+ exitstatus = status;
+cmddone:
+ freestdout();
+ commandname = savecmdname;
+ handler = savehandler;
+
+ return i;
+}
+
+STATIC int
+evalfun(struct funcnode *func, int argc, char **argv, int flags)
+{
+ volatile struct shparam saveparam;
+ struct jmploc *volatile savehandler;
+ struct jmploc jmploc;
+ int e;
+ int savefuncline;
+
+ saveparam = shellparam;
+ savefuncline = funcline;
+ savehandler = handler;
+ if ((e = setjmp(jmploc.loc))) {
+ goto funcdone;
+ }
+ INTOFF;
+ handler = &jmploc;
+ shellparam.malloc = 0;
+ func->count++;
+ funcline = func->n.ndefun.linno;
+ INTON;
+ shellparam.nparam = argc - 1;
+ shellparam.p = argv + 1;
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+ pushlocalvars();
+ evaltree(func->n.ndefun.body, flags & EV_TESTED);
+ poplocalvars(0);
+funcdone:
+ INTOFF;
+ funcline = savefuncline;
+ freefunc(func);
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ handler = savehandler;
+ INTON;
+ evalskip &= ~SKIPFUNC;
+ return e;
+}
+
+
+/*
+ * Search for a command. This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child. The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+STATIC void
+prehash(union node *n)
+{
+ struct cmdentry entry;
+
+ if (n->type == NCMD && n->ncmd.args)
+ if (goodname(n->ncmd.args->narg.text))
+ find_command(n->ncmd.args->narg.text, &entry, 0,
+ pathval());
+}
+
+
+
+/*
+ * Builtin commands. Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given.
+ */
+
+STATIC int
+bltincmd(int argc, char **argv)
+{
+ /*
+ * Preserve exitstatus of a previous possible redirection
+ * as POSIX mandates
+ */
+ return back_exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands. Break, continue, and return are
+ * all handled by setting the evalskip flag. The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them. The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return. (The latter is always 1.) It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+int
+breakcmd(int argc, char **argv)
+{
+ int n = argc > 1 ? number(argv[1]) : 1;
+
+ if (n <= 0)
+ badnum(argv[1]);
+ if (n > loopnest)
+ n = loopnest;
+ if (n > 0) {
+ evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+ skipcount = n;
+ }
+ return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+int
+returncmd(int argc, char **argv)
+{
+ /*
+ * If called outside a function, do what ksh does;
+ * skip the rest of the file.
+ */
+ evalskip = SKIPFUNC;
+ return argv[1] ? number(argv[1]) : exitstatus;
+}
+
+
+int
+falsecmd(int argc, char **argv)
+{
+ return 1;
+}
+
+
+int
+truecmd(int argc, char **argv)
+{
+ return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
+ if (argc > 1) {
+ iflag = 0; /* exit on error */
+ mflag = 0;
+ optschanged();
+ shellexec(argv + 1, pathval(), 0);
+ }
+ return 0;
+}
+
+
+STATIC int
+eprintlist(struct output *out, struct strlist *sp, int sep)
+{
+ while (sp) {
+ const char *p;
+
+ p = " %s";
+ p += (1 - sep);
+ sep |= 1;
+ outfmt(out, p, sp->text);
+ sp = sp->next;
+ }
+
+ return sep;
+}
diff --git a/usr/dash/eval.h b/usr/dash/eval.h
new file mode 100644
index 0000000..5ccfa9f
--- /dev/null
+++ b/usr/dash/eval.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)eval.h 8.2 (Berkeley) 5/4/95
+ */
+
+extern char *commandname; /* currently executing command */
+extern int exitstatus; /* exit status of last command */
+extern int back_exitstatus; /* exit status of backquoted command */
+
+
+struct backcmd { /* result of evalbackcmd */
+ int fd; /* file descriptor to read from */
+ char *buf; /* buffer */
+ int nleft; /* number of chars in buffer */
+ struct job *jp; /* job structure for command */
+};
+
+int evalstring(char *, int);
+union node; /* BLETCH for ansi C */
+void evaltree(union node *, int);
+void evalbackcmd(union node *, struct backcmd *);
+
+extern int evalskip;
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK (1 << 0)
+#define SKIPCONT (1 << 1)
+#define SKIPFUNC (1 << 2)
diff --git a/usr/dash/exec.c b/usr/dash/exec.c
new file mode 100644
index 0000000..79e2007
--- /dev/null
+++ b/usr/dash/exec.c
@@ -0,0 +1,859 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE 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/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "parser.h"
+#include "redir.h"
+#include "eval.h"
+#include "exec.h"
+#include "builtins.h"
+#include "var.h"
+#include "options.h"
+#include "output.h"
+#include "syntax.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
+#include "system.h"
+
+
+#define CMDTABLESIZE 31 /* should be prime */
+#define ARB 1 /* actual size determined at run time */
+
+
+
+struct tblentry {
+ struct tblentry *next; /* next entry in hash chain */
+ union param param; /* definition of builtin function */
+ short cmdtype; /* index identifying command */
+ char rehash; /* if set, cd done since entry created */
+ char cmdname[ARB]; /* name of command */
+};
+
+
+STATIC struct tblentry *cmdtable[CMDTABLESIZE];
+STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
+
+
+STATIC void tryexec(char *, char **, char **);
+STATIC void printentry(struct tblentry *);
+STATIC void clearcmdentry(int);
+STATIC struct tblentry *cmdlookup(const char *, int);
+STATIC void delete_cmd_entry(void);
+STATIC void addcmdentry(char *, struct cmdentry *);
+STATIC int describe_command(struct output *, char *, int);
+
+
+/*
+ * Exec a program. Never returns. If you change this routine, you may
+ * have to change the find_command routine as well.
+ */
+
+void
+shellexec(char **argv, const char *path, int idx)
+{
+ char *cmdname;
+ int e;
+ char **envp;
+ int exerrno;
+
+ envp = environment();
+ if (strchr(argv[0], '/') != NULL) {
+ tryexec(argv[0], argv, envp);
+ e = errno;
+ } else {
+ e = ENOENT;
+ while ((cmdname = padvance(&path, argv[0])) != NULL) {
+ if (--idx < 0 && pathopt == NULL) {
+ tryexec(cmdname, argv, envp);
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ }
+ stunalloc(cmdname);
+ }
+ }
+
+ /* Map to POSIX errors */
+ switch (e) {
+ case EACCES:
+ exerrno = 126;
+ break;
+ case ENOENT:
+ exerrno = 127;
+ break;
+ default:
+ exerrno = 2;
+ break;
+ }
+ exitstatus = exerrno;
+ TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
+ argv[0], e, suppressint ));
+ exerror(EXEXIT, "%s: %s", argv[0], errmsg(e, E_EXEC));
+ /* NOTREACHED */
+}
+
+
+STATIC void
+tryexec(char *cmd, char **argv, char **envp)
+{
+ char *const path_bshell = _PATH_BSHELL;
+
+repeat:
+#ifdef SYSV
+ do {
+ execve(cmd, argv, envp);
+ } while (errno == EINTR);
+#else
+ execve(cmd, argv, envp);
+#endif
+ if (cmd != path_bshell && errno == ENOEXEC) {
+ *argv-- = cmd;
+ *argv = cmd = path_bshell;
+ goto repeat;
+ }
+}
+
+
+
+/*
+ * Do a path search. The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds. Successive calls to padvance will return
+ * the possible path expansions in sequence. If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+const char *pathopt;
+
+char *
+padvance(const char **path, const char *name)
+{
+ const char *p;
+ char *q;
+ const char *start;
+ size_t len;
+
+ if (*path == NULL)
+ return NULL;
+ start = *path;
+ for (p = start ; *p && *p != ':' && *p != '%' ; p++);
+ len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
+ while (stackblocksize() < len)
+ growstackblock();
+ q = stackblock();
+ if (p != start) {
+ memcpy(q, start, p - start);
+ q += p - start;
+ *q++ = '/';
+ }
+ strcpy(q, name);
+ pathopt = NULL;
+ if (*p == '%') {
+ pathopt = ++p;
+ while (*p && *p != ':') p++;
+ }
+ if (*p == ':')
+ *path = p + 1;
+ else
+ *path = NULL;
+ return stalloc(len);
+}
+
+
+
+/*** Command hashing code ***/
+
+
+int
+hashcmd(int argc, char **argv)
+{
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+ int c;
+ struct cmdentry entry;
+ char *name;
+
+ while ((c = nextopt("r")) != '\0') {
+ clearcmdentry(0);
+ return 0;
+ }
+ if (*argptr == NULL) {
+ for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (cmdp->cmdtype == CMDNORMAL)
+ printentry(cmdp);
+ }
+ }
+ return 0;
+ }
+ c = 0;
+ while ((name = *argptr) != NULL) {
+ if ((cmdp = cmdlookup(name, 0)) != NULL
+ && (cmdp->cmdtype == CMDNORMAL
+ || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
+ delete_cmd_entry();
+ find_command(name, &entry, DO_ERR, pathval());
+ if (entry.cmdtype == CMDUNKNOWN)
+ c = 1;
+ argptr++;
+ }
+ return c;
+}
+
+
+STATIC void
+printentry(struct tblentry *cmdp)
+{
+ int idx;
+ const char *path;
+ char *name;
+
+ idx = cmdp->param.index;
+ path = pathval();
+ do {
+ name = padvance(&path, cmdp->cmdname);
+ stunalloc(name);
+ } while (--idx >= 0);
+ out1str(name);
+ out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
+}
+
+
+
+/*
+ * Resolve a command name. If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+void
+find_command(char *name, struct cmdentry *entry, int act, const char *path)
+{
+ struct tblentry *cmdp;
+ int idx;
+ int prev;
+ char *fullname;
+ struct stat64 statb;
+ int e;
+ int updatetbl;
+ struct builtincmd *bcmd;
+
+ /* If name contains a slash, don't use PATH or hash table */
+ if (strchr(name, '/') != NULL) {
+ entry->u.index = -1;
+ if (act & DO_ABS) {
+ while (stat64(name, &statb) < 0) {
+#ifdef SYSV
+ if (errno == EINTR)
+ continue;
+#endif
+ entry->cmdtype = CMDUNKNOWN;
+ return;
+ }
+ }
+ entry->cmdtype = CMDNORMAL;
+ return;
+ }
+
+ updatetbl = (path == pathval());
+ if (!updatetbl) {
+ act |= DO_ALTPATH;
+ if (strstr(path, "%builtin") != NULL)
+ act |= DO_ALTBLTIN;
+ }
+
+ /* If name is in the table, check answer will be ok */
+ if ((cmdp = cmdlookup(name, 0)) != NULL) {
+ int bit;
+
+ switch (cmdp->cmdtype) {
+ default:
+#if DEBUG
+ abort();
+#endif
+ case CMDNORMAL:
+ bit = DO_ALTPATH;
+ break;
+ case CMDFUNCTION:
+ bit = DO_NOFUNC;
+ break;
+ case CMDBUILTIN:
+ bit = DO_ALTBLTIN;
+ break;
+ }
+ if (act & bit) {
+ updatetbl = 0;
+ cmdp = NULL;
+ } else if (cmdp->rehash == 0)
+ /* if not invalidated by cd, we're done */
+ goto success;
+ }
+
+ /* If %builtin not in path, check for builtin next */
+ bcmd = find_builtin(name);
+ if (bcmd && (bcmd->flags & BUILTIN_REGULAR || (
+ act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
+ )))
+ goto builtin_success;
+
+ /* We have to search path. */
+ prev = -1; /* where to start */
+ if (cmdp && cmdp->rehash) { /* doing a rehash */
+ if (cmdp->cmdtype == CMDBUILTIN)
+ prev = builtinloc;
+ else
+ prev = cmdp->param.index;
+ }
+
+ e = ENOENT;
+ idx = -1;
+loop:
+ while ((fullname = padvance(&path, name)) != NULL) {
+ stunalloc(fullname);
+ idx++;
+ if (pathopt) {
+ if (prefix(pathopt, "builtin")) {
+ if (bcmd)
+ goto builtin_success;
+ continue;
+ } else if (!(act & DO_NOFUNC) &&
+ prefix(pathopt, "func")) {
+ /* handled below */
+ } else {
+ /* ignore unimplemented options */
+ continue;
+ }
+ }
+ /* if rehash, don't redo absolute path names */
+ if (fullname[0] == '/' && idx <= prev) {
+ if (idx < prev)
+ continue;
+ TRACE(("searchexec \"%s\": no change\n", name));
+ goto success;
+ }
+ while (stat64(fullname, &statb) < 0) {
+#ifdef SYSV
+ if (errno == EINTR)
+ continue;
+#endif
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ goto loop;
+ }
+ e = EACCES; /* if we fail, this will be the error */
+ if (!S_ISREG(statb.st_mode))
+ continue;
+ if (pathopt) { /* this is a %func directory */
+ stalloc(strlen(fullname) + 1);
+ readcmdfile(fullname);
+ if ((cmdp = cmdlookup(name, 0)) == NULL ||
+ cmdp->cmdtype != CMDFUNCTION)
+ sh_error("%s not defined in %s", name,
+ fullname);
+ stunalloc(fullname);
+ goto success;
+ }
+#ifdef notdef
+ /* XXX this code stops root executing stuff, and is buggy
+ if you need a group from the group list. */
+ if (statb.st_uid == geteuid()) {
+ if ((statb.st_mode & 0100) == 0)
+ goto loop;
+ } else if (statb.st_gid == getegid()) {
+ if ((statb.st_mode & 010) == 0)
+ goto loop;
+ } else {
+ if ((statb.st_mode & 01) == 0)
+ goto loop;
+ }
+#endif
+ TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+ if (!updatetbl) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = idx;
+ return;
+ }
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ cmdp->cmdtype = CMDNORMAL;
+ cmdp->param.index = idx;
+ INTON;
+ goto success;
+ }
+
+ /* We failed. If there was an entry for this command, delete it */
+ if (cmdp && updatetbl)
+ delete_cmd_entry();
+ if (act & DO_ERR)
+ sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
+ entry->cmdtype = CMDUNKNOWN;
+ return;
+
+builtin_success:
+ if (!updatetbl) {
+ entry->cmdtype = CMDBUILTIN;
+ entry->u.cmd = bcmd;
+ return;
+ }
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ cmdp->cmdtype = CMDBUILTIN;
+ cmdp->param.cmd = bcmd;
+ INTON;
+success:
+ cmdp->rehash = 0;
+ entry->cmdtype = cmdp->cmdtype;
+ entry->u = cmdp->param;
+}
+
+
+
+/*
+ * Search the table of builtin commands.
+ */
+
+struct builtincmd *
+find_builtin(const char *name)
+{
+ struct builtincmd *bp;
+
+ bp = bsearch(
+ &name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
+ pstrcmp
+ );
+ return bp;
+}
+
+
+
+/*
+ * Called when a cd is done. Marks all commands so the next time they
+ * are executed they will be rehashed.
+ */
+
+void
+hashcd(void)
+{
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+
+ for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (cmdp->cmdtype == CMDNORMAL || (
+ cmdp->cmdtype == CMDBUILTIN &&
+ !(cmdp->param.cmd->flags & BUILTIN_REGULAR) &&
+ builtinloc > 0
+ ))
+ cmdp->rehash = 1;
+ }
+ }
+}
+
+
+
+/*
+ * Fix command hash table when PATH changed.
+ * Called before PATH is changed. The argument is the new value of PATH;
+ * pathval() still returns the old value at this point.
+ * Called with interrupts off.
+ */
+
+void
+changepath(const char *newval)
+{
+ const char *old, *new;
+ int idx;
+ int firstchange;
+ int bltin;
+
+ old = pathval();
+ new = newval;
+ firstchange = 9999; /* assume no change */
+ idx = 0;
+ bltin = -1;
+ for (;;) {
+ if (*old != *new) {
+ firstchange = idx;
+ if ((*old == '\0' && *new == ':')
+ || (*old == ':' && *new == '\0'))
+ firstchange++;
+ old = new; /* ignore subsequent differences */
+ }
+ if (*new == '\0')
+ break;
+ if (*new == '%' && bltin < 0 && prefix(new + 1, "builtin"))
+ bltin = idx;
+ if (*new == ':') {
+ idx++;
+ }
+ new++, old++;
+ }
+ if (builtinloc < 0 && bltin >= 0)
+ builtinloc = bltin; /* zap builtins */
+ if (builtinloc >= 0 && bltin < 0)
+ firstchange = 0;
+ clearcmdentry(firstchange);
+ builtinloc = bltin;
+}
+
+
+/*
+ * Clear out command entries. The argument specifies the first entry in
+ * PATH which has changed.
+ */
+
+STATIC void
+clearcmdentry(int firstchange)
+{
+ struct tblentry **tblp;
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+
+ INTOFF;
+ for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+ pp = tblp;
+ while ((cmdp = *pp) != NULL) {
+ if ((cmdp->cmdtype == CMDNORMAL &&
+ cmdp->param.index >= firstchange)
+ || (cmdp->cmdtype == CMDBUILTIN &&
+ builtinloc >= firstchange)) {
+ *pp = cmdp->next;
+ ckfree(cmdp);
+ } else {
+ pp = &cmdp->next;
+ }
+ }
+ }
+ INTON;
+}
+
+
+
+/*
+ * Locate a command in the command hash table. If "add" is nonzero,
+ * add the command to the table if it is not already present. The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ *
+ * Interrupts must be off if called with add != 0.
+ */
+
+struct tblentry **lastcmdentry;
+
+
+STATIC struct tblentry *
+cmdlookup(const char *name, int add)
+{
+ unsigned int hashval;
+ const char *p;
+ struct tblentry *cmdp;
+ struct tblentry **pp;
+
+ p = name;
+ hashval = (unsigned char)*p << 4;
+ while (*p)
+ hashval += (unsigned char)*p++;
+ hashval &= 0x7FFF;
+ pp = &cmdtable[hashval % CMDTABLESIZE];
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (equal(cmdp->cmdname, name))
+ break;
+ pp = &cmdp->next;
+ }
+ if (add && cmdp == NULL) {
+ cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
+ + strlen(name) + 1);
+ cmdp->next = NULL;
+ cmdp->cmdtype = CMDUNKNOWN;
+ strcpy(cmdp->cmdname, name);
+ }
+ lastcmdentry = pp;
+ return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+STATIC void
+delete_cmd_entry(void)
+{
+ struct tblentry *cmdp;
+
+ INTOFF;
+ cmdp = *lastcmdentry;
+ *lastcmdentry = cmdp->next;
+ if (cmdp->cmdtype == CMDFUNCTION)
+ freefunc(cmdp->param.func);
+ ckfree(cmdp);
+ INTON;
+}
+
+
+
+#ifdef notdef
+void
+getcmdentry(char *name, struct cmdentry *entry)
+{
+ struct tblentry *cmdp = cmdlookup(name, 0);
+
+ if (cmdp) {
+ entry->u = cmdp->param;
+ entry->cmdtype = cmdp->cmdtype;
+ } else {
+ entry->cmdtype = CMDUNKNOWN;
+ entry->u.index = 0;
+ }
+}
+#endif
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name - except special builtins.
+ */
+
+STATIC void
+addcmdentry(char *name, struct cmdentry *entry)
+{
+ struct tblentry *cmdp;
+
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION) {
+ freefunc(cmdp->param.func);
+ }
+ cmdp->cmdtype = entry->cmdtype;
+ cmdp->param = entry->u;
+ cmdp->rehash = 0;
+}
+
+
+/*
+ * Define a shell function.
+ */
+
+void
+defun(union node *func)
+{
+ struct cmdentry entry;
+
+ INTOFF;
+ entry.cmdtype = CMDFUNCTION;
+ entry.u.func = copyfunc(func);
+ addcmdentry(func->ndefun.text, &entry);
+ INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ */
+
+void
+unsetfunc(const char *name)
+{
+ struct tblentry *cmdp;
+
+ if ((cmdp = cmdlookup(name, 0)) != NULL &&
+ cmdp->cmdtype == CMDFUNCTION)
+ delete_cmd_entry();
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+ int i;
+ int err = 0;
+
+ for (i = 1; i < argc; i++) {
+ err |= describe_command(out1, argv[i], 1);
+ }
+ return err;
+}
+
+STATIC int
+describe_command(out, command, verbose)
+ struct output *out;
+ char *command;
+ int verbose;
+{
+ struct cmdentry entry;
+ struct tblentry *cmdp;
+ const struct alias *ap;
+ const char *path = pathval();
+
+ if (verbose) {
+ outstr(command, out);
+ }
+
+ /* First look at the keywords */
+ if (findkwd(command)) {
+ outstr(verbose ? " is a shell keyword" : command, out);
+ goto out;
+ }
+
+ /* Then look at the aliases */
+ if ((ap = lookupalias(command, 0)) != NULL) {
+ if (verbose) {
+ outfmt(out, " is an alias for %s", ap->val);
+ } else {
+ outstr("alias ", out);
+ printalias(ap);
+ return 0;
+ }
+ goto out;
+ }
+
+ /* Then check if it is a tracked alias */
+ if ((cmdp = cmdlookup(command, 0)) != NULL) {
+ entry.cmdtype = cmdp->cmdtype;
+ entry.u = cmdp->param;
+ } else {
+ /* Finally use brute force */
+ find_command(command, &entry, DO_ABS, path);
+ }
+
+ switch (entry.cmdtype) {
+ case CMDNORMAL: {
+ int j = entry.u.index;
+ char *p;
+ if (j == -1) {
+ p = command;
+ } else {
+ do {
+ p = padvance(&path, command);
+ stunalloc(p);
+ } while (--j >= 0);
+ }
+ if (verbose) {
+ outfmt(
+ out, " is%s %s",
+ cmdp ? " a tracked alias for" : nullstr, p
+ );
+ } else {
+ outstr(p, out);
+ }
+ break;
+ }
+
+ case CMDFUNCTION:
+ if (verbose) {
+ outstr(" is a shell function", out);
+ } else {
+ outstr(command, out);
+ }
+ break;
+
+ case CMDBUILTIN:
+ if (verbose) {
+ outfmt(
+ out, " is a %sshell builtin",
+ entry.u.cmd->flags & BUILTIN_SPECIAL ?
+ "special " : nullstr
+ );
+ } else {
+ outstr(command, out);
+ }
+ break;
+
+ default:
+ if (verbose) {
+ outstr(": not found\n", out);
+ }
+ return 127;
+ }
+
+out:
+ outc('\n', out);
+ return 0;
+}
+
+int
+commandcmd(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *cmd;
+ int c;
+ enum {
+ VERIFY_BRIEF = 1,
+ VERIFY_VERBOSE = 2,
+ } verify = 0;
+
+ while ((c = nextopt("pvV")) != '\0')
+ if (c == 'V')
+ verify |= VERIFY_VERBOSE;
+ else if (c == 'v')
+ verify |= VERIFY_BRIEF;
+#ifdef DEBUG
+ else if (c != 'p')
+ abort();
+#endif
+
+ cmd = *argptr;
+ if (verify && cmd)
+ return describe_command(out1, cmd, verify - VERIFY_BRIEF);
+
+ return 0;
+}
diff --git a/usr/dash/exec.h b/usr/dash/exec.h
new file mode 100644
index 0000000..9ccb305
--- /dev/null
+++ b/usr/dash/exec.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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.h 8.3 (Berkeley) 6/8/95
+ */
+
+/* values of cmdtype */
+#define CMDUNKNOWN -1 /* no entry in table for command */
+#define CMDNORMAL 0 /* command is an executable program */
+#define CMDFUNCTION 1 /* command is a shell function */
+#define CMDBUILTIN 2 /* command is a shell builtin */
+
+
+struct cmdentry {
+ int cmdtype;
+ union param {
+ int index;
+ const struct builtincmd *cmd;
+ struct funcnode *func;
+ } u;
+};
+
+
+/* action to find_command() */
+#define DO_ERR 0x01 /* prints errors */
+#define DO_ABS 0x02 /* checks absolute paths */
+#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
+#define DO_ALTPATH 0x08 /* using alternate path */
+#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
+
+extern const char *pathopt; /* set by padvance */
+
+void shellexec(char **, const char *, int)
+ __attribute__((__noreturn__));
+char *padvance(const char **, const char *);
+int hashcmd(int, char **);
+void find_command(char *, struct cmdentry *, int, const char *);
+struct builtincmd *find_builtin(const char *);
+void hashcd(void);
+void changepath(const char *);
+#ifdef notdef
+void getcmdentry(char *, struct cmdentry *);
+#endif
+void defun(union node *);
+void unsetfunc(const char *);
+int typecmd(int, char **);
+int commandcmd(int, char **);
diff --git a/usr/dash/expand.c b/usr/dash/expand.c
new file mode 100644
index 0000000..355e924
--- /dev/null
+++ b/usr/dash/expand.c
@@ -0,0 +1,1728 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE 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/time.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#ifdef HAVE_GETPWNAM
+#include <pwd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+#include <fnmatch.h>
+#ifdef HAVE_GLOB
+#include <glob.h>
+#endif
+#include <ctype.h>
+
+/*
+ * Routines to expand arguments to commands. We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "eval.h"
+#include "expand.h"
+#include "syntax.h"
+#include "parser.h"
+#include "jobs.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "show.h"
+#include "system.h"
+
+/*
+ * _rmescape() flags
+ */
+#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
+#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
+#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
+#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
+
+/* Add CTLESC when necessary. */
+#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
+/* Do not skip NUL characters. */
+#define QUOTES_KEEPNUL EXP_TILDE
+
+/*
+ * Structure specifying which parts of the string should be searched
+ * for IFS characters.
+ */
+
+struct ifsregion {
+ struct ifsregion *next; /* next region in list */
+ int begoff; /* offset of start of region */
+ int endoff; /* offset of end of region */
+ int nulonly; /* search for nul bytes only */
+};
+
+/* output of current string */
+static char *expdest;
+/* list of back quote expressions */
+static struct nodelist *argbackq;
+/* first struct in list of ifs regions */
+static struct ifsregion ifsfirst;
+/* last struct in list */
+static struct ifsregion *ifslastp;
+/* holds expanded arg list */
+static struct arglist exparg;
+
+STATIC void argstr(char *, int);
+STATIC char *exptilde(char *, char *, int);
+STATIC void expbackq(union node *, int);
+STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
+STATIC char *evalvar(char *, int);
+STATIC size_t strtodest(const char *, const char *, int);
+STATIC void memtodest(const char *, size_t, const char *, int);
+STATIC ssize_t varvalue(char *, int, int);
+STATIC void expandmeta(struct strlist *, int);
+#ifdef HAVE_GLOB
+STATIC void addglob(const glob_t *);
+#else
+STATIC void expmeta(char *, char *);
+STATIC struct strlist *expsort(struct strlist *);
+STATIC struct strlist *msort(struct strlist *, int);
+#endif
+STATIC void addfname(char *);
+STATIC int patmatch(char *, const char *);
+#ifndef HAVE_FNMATCH
+STATIC int pmatch(const char *, const char *);
+#else
+#define pmatch(a, b) !fnmatch((a), (b), 0)
+#endif
+STATIC int cvtnum(intmax_t);
+STATIC size_t esclen(const char *, const char *);
+STATIC char *scanleft(char *, char *, char *, char *, int, int);
+STATIC char *scanright(char *, char *, char *, char *, int, int);
+STATIC void varunset(const char *, const char *, const char *, int)
+ __attribute__((__noreturn__));
+
+
+/*
+ * Prepare a pattern for a glob(3) call.
+ *
+ * Returns an stalloced string.
+ */
+
+STATIC inline char *
+preglob(const char *pattern, int flag) {
+ flag |= RMESCAPE_GLOB;
+ return _rmescapes((char *)pattern, flag);
+}
+
+
+STATIC size_t
+esclen(const char *start, const char *p) {
+ size_t esc = 0;
+
+ while (p > start && *--p == (char)CTLESC) {
+ esc++;
+ }
+ return esc;
+}
+
+
+static inline const char *getpwhome(const char *name)
+{
+#ifdef HAVE_GETPWNAM
+ struct passwd *pw = getpwnam(name);
+ return pw ? pw->pw_dir : 0;
+#else
+ return 0;
+#endif
+}
+
+
+/*
+ * Perform variable substitution and command substitution on an argument,
+ * placing the resulting list of arguments in arglist. If EXP_FULL is true,
+ * perform splitting and file name expansion. When arglist is NULL, perform
+ * here document expansion.
+ */
+
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+ struct strlist *sp;
+ char *p;
+
+ argbackq = arg->narg.backquote;
+ STARTSTACKSTR(expdest);
+ argstr(arg->narg.text, flag);
+ p = _STPUTC('\0', expdest);
+ expdest = p - 1;
+ if (arglist == NULL) {
+ /* here document expanded */
+ goto out;
+ }
+ p = grabstackstr(p);
+ exparg.lastp = &exparg.list;
+ /*
+ * TODO - EXP_REDIR
+ */
+ if (flag & EXP_FULL) {
+ ifsbreakup(p, &exparg);
+ *exparg.lastp = NULL;
+ exparg.lastp = &exparg.list;
+ expandmeta(exparg.list, flag);
+ } else {
+ sp = (struct strlist *)stalloc(sizeof (struct strlist));
+ sp->text = p;
+ *exparg.lastp = sp;
+ exparg.lastp = &sp->next;
+ }
+ *exparg.lastp = NULL;
+ if (exparg.list) {
+ *arglist->lastp = exparg.list;
+ arglist->lastp = exparg.lastp;
+ }
+
+out:
+ ifsfree();
+}
+
+
+
+/*
+ * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
+ * characters to allow for further processing. Otherwise treat
+ * $@ like $* since no splitting will be performed.
+ */
+
+STATIC void
+argstr(char *p, int flag)
+{
+ static const char spclchars[] = {
+ '=',
+ ':',
+ CTLQUOTEMARK,
+ CTLENDVAR,
+ CTLESC,
+ CTLVAR,
+ CTLBACKQ,
+ CTLENDARI,
+ 0
+ };
+ const char *reject = spclchars;
+ int c;
+ int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
+ int inquotes;
+ size_t length;
+ int startloc;
+
+ if (!(flag & EXP_VARTILDE)) {
+ reject += 2;
+ } else if (flag & EXP_VARTILDE2) {
+ reject++;
+ }
+ inquotes = 0;
+ length = 0;
+ if (flag & EXP_TILDE) {
+ char *q;
+
+ flag &= ~EXP_TILDE;
+tilde:
+ q = p;
+ if (*q == '~')
+ p = exptilde(p, q, flag);
+ }
+start:
+ startloc = expdest - (char *)stackblock();
+ for (;;) {
+ length += strcspn(p + length, reject);
+ c = (signed char)p[length];
+ if (c && (!(c & 0x80) || c == CTLENDARI)) {
+ /* c == '=' || c == ':' || c == CTLENDARI */
+ length++;
+ }
+ if (length > 0) {
+ int newloc;
+ expdest = stnputs(p, length, expdest);
+ newloc = expdest - (char *)stackblock();
+ if (breakall && !inquotes && newloc > startloc) {
+ recordregion(startloc, newloc, 0);
+ }
+ startloc = newloc;
+ }
+ p += length + 1;
+ length = 0;
+
+ switch (c) {
+ case '\0':
+ goto breakloop;
+ case '=':
+ if (flag & EXP_VARTILDE2) {
+ p--;
+ continue;
+ }
+ flag |= EXP_VARTILDE2;
+ reject++;
+ /* fall through */
+ case ':':
+ /*
+ * sort of a hack - expand tildes in variable
+ * assignments (after the first '=' and after ':'s).
+ */
+ if (*--p == '~') {
+ goto tilde;
+ }
+ continue;
+ }
+
+ switch (c) {
+ case CTLENDVAR: /* ??? */
+ goto breakloop;
+ case CTLQUOTEMARK:
+ inquotes ^= EXP_QUOTED;
+ /* "$@" syntax adherence hack */
+ if (inquotes && !memcmp(p, dolatstr + 1,
+ DOLATSTRLEN - 1)) {
+ p = evalvar(p + 1, flag | inquotes) + 1;
+ goto start;
+ }
+addquote:
+ if (flag & QUOTES_ESC) {
+ p--;
+ length++;
+ startloc++;
+ }
+ break;
+ case CTLESC:
+ startloc++;
+ length++;
+
+ /*
+ * Quoted parameter expansion pattern: remove quote
+ * unless inside inner quotes or we have a literal
+ * backslash.
+ */
+ if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
+ EXP_QPAT && *p != '\\')
+ break;
+
+ goto addquote;
+ case CTLVAR:
+ p = evalvar(p, flag | inquotes);
+ goto start;
+ case CTLBACKQ:
+ expbackq(argbackq->n, flag | inquotes);
+ argbackq = argbackq->next;
+ goto start;
+ case CTLENDARI:
+ p--;
+ expari(flag | inquotes);
+ goto start;
+ }
+ }
+breakloop:
+ ;
+}
+
+STATIC char *
+exptilde(char *startp, char *p, int flag)
+{
+ signed char c;
+ char *name;
+ const char *home;
+ int quotes = flag & QUOTES_ESC;
+
+ name = p + 1;
+
+ while ((c = *++p) != '\0') {
+ switch(c) {
+ case CTLESC:
+ return (startp);
+ case CTLQUOTEMARK:
+ return (startp);
+ case ':':
+ if (flag & EXP_VARTILDE)
+ goto done;
+ break;
+ case '/':
+ case CTLENDVAR:
+ goto done;
+ }
+ }
+done:
+ *p = '\0';
+ if (*name == '\0') {
+ home = lookupvar(homestr);
+ } else {
+ home = getpwhome(name);
+ }
+ if (!home || !*home)
+ goto lose;
+ *p = c;
+ strtodest(home, SQSYNTAX, quotes);
+ return (p);
+lose:
+ *p = c;
+ return (startp);
+}
+
+
+void
+removerecordregions(int endoff)
+{
+ if (ifslastp == NULL)
+ return;
+
+ if (ifsfirst.endoff > endoff) {
+ while (ifsfirst.next != NULL) {
+ struct ifsregion *ifsp;
+ INTOFF;
+ ifsp = ifsfirst.next->next;
+ ckfree(ifsfirst.next);
+ ifsfirst.next = ifsp;
+ INTON;
+ }
+ if (ifsfirst.begoff > endoff)
+ ifslastp = NULL;
+ else {
+ ifslastp = &ifsfirst;
+ ifsfirst.endoff = endoff;
+ }
+ return;
+ }
+
+ ifslastp = &ifsfirst;
+ while (ifslastp->next && ifslastp->next->begoff < endoff)
+ ifslastp=ifslastp->next;
+ while (ifslastp->next != NULL) {
+ struct ifsregion *ifsp;
+ INTOFF;
+ ifsp = ifslastp->next->next;
+ ckfree(ifslastp->next);
+ ifslastp->next = ifsp;
+ INTON;
+ }
+ if (ifslastp->endoff > endoff)
+ ifslastp->endoff = endoff;
+}
+
+
+/*
+ * Expand arithmetic expression. Backup to start of expression,
+ * evaluate, place result in (backed up) result, adjust string position.
+ */
+void
+expari(int flag)
+{
+ struct stackmark sm;
+ char *p, *start;
+ int begoff;
+ int len;
+ intmax_t result;
+
+ /* ifsfree(); */
+
+ /*
+ * This routine is slightly over-complicated for
+ * efficiency. Next we scan backwards looking for the
+ * start of arithmetic.
+ */
+ start = stackblock();
+ p = expdest;
+ pushstackmark(&sm, p - start);
+ *--p = '\0';
+ p--;
+ do {
+ int esc;
+
+ while (*p != (char)CTLARI) {
+ p--;
+#ifdef DEBUG
+ if (p < start) {
+ sh_error("missing CTLARI (shouldn't happen)");
+ }
+#endif
+ }
+
+ esc = esclen(start, p);
+ if (!(esc % 2)) {
+ break;
+ }
+
+ p -= esc + 1;
+ } while (1);
+
+ begoff = p - start;
+
+ removerecordregions(begoff);
+
+ expdest = p;
+
+ if (likely(flag & QUOTES_ESC))
+ rmescapes(p + 1);
+
+ result = arith(p + 1);
+ popstackmark(&sm);
+
+ len = cvtnum(result);
+
+ if (likely(!(flag & EXP_QUOTED)))
+ recordregion(begoff, begoff + len, 0);
+}
+
+
+/*
+ * Expand stuff in backwards quotes.
+ */
+
+STATIC void
+expbackq(union node *cmd, int flag)
+{
+ struct backcmd in;
+ int i;
+ char buf[128];
+ char *p;
+ char *dest;
+ int startloc;
+ char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
+ struct stackmark smark;
+
+ INTOFF;
+ startloc = expdest - (char *)stackblock();
+ pushstackmark(&smark, startloc);
+ evalbackcmd(cmd, (struct backcmd *) &in);
+ popstackmark(&smark);
+
+ p = in.buf;
+ i = in.nleft;
+ if (i == 0)
+ goto read;
+ for (;;) {
+ memtodest(p, i, syntax, flag & QUOTES_ESC);
+read:
+ if (in.fd < 0)
+ break;
+ do {
+ i = read(in.fd, buf, sizeof buf);
+ } while (i < 0 && errno == EINTR);
+ TRACE(("expbackq: read returns %d\n", i));
+ if (i <= 0)
+ break;
+ p = buf;
+ }
+
+ if (in.buf)
+ ckfree(in.buf);
+ if (in.fd >= 0) {
+ close(in.fd);
+ back_exitstatus = waitforjob(in.jp);
+ }
+ INTON;
+
+ /* Eat all trailing newlines */
+ dest = expdest;
+ for (; dest > (char *)stackblock() && dest[-1] == '\n';)
+ STUNPUTC(dest);
+ expdest = dest;
+
+ if (!(flag & EXP_QUOTED))
+ recordregion(startloc, dest - (char *)stackblock(), 0);
+ TRACE(("evalbackq: size=%d: \"%.*s\"\n",
+ (dest - (char *)stackblock()) - startloc,
+ (dest - (char *)stackblock()) - startloc,
+ stackblock() + startloc));
+}
+
+
+STATIC char *
+scanleft(
+ char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+ int zero
+) {
+ char *loc;
+ char *loc2;
+ char c;
+
+ loc = startp;
+ loc2 = rmesc;
+ do {
+ int match;
+ const char *s = loc2;
+ c = *loc2;
+ if (zero) {
+ *loc2 = '\0';
+ s = rmesc;
+ }
+ match = pmatch(str, s);
+ *loc2 = c;
+ if (match)
+ return loc;
+ if (quotes && *loc == (char)CTLESC)
+ loc++;
+ loc++;
+ loc2++;
+ } while (c);
+ return 0;
+}
+
+
+STATIC char *
+scanright(
+ char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+ int zero
+) {
+ int esc = 0;
+ char *loc;
+ char *loc2;
+
+ for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
+ int match;
+ char c = *loc2;
+ const char *s = loc2;
+ if (zero) {
+ *loc2 = '\0';
+ s = rmesc;
+ }
+ match = pmatch(str, s);
+ *loc2 = c;
+ if (match)
+ return loc;
+ loc--;
+ if (quotes) {
+ if (--esc < 0) {
+ esc = esclen(startp, loc);
+ }
+ if (esc % 2) {
+ esc--;
+ loc--;
+ }
+ }
+ }
+ return 0;
+}
+
+STATIC const char *
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag)
+{
+ int quotes = flag & QUOTES_ESC;
+ char *startp;
+ char *loc;
+ struct nodelist *saveargbackq = argbackq;
+ int amount;
+ char *rmesc, *rmescend;
+ int zero;
+ char *(*scan)(char *, char *, char *, char *, int , int);
+
+ argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
+ (flag & EXP_QUOTED ? EXP_QPAT : EXP_CASE) : 0));
+ STPUTC('\0', expdest);
+ argbackq = saveargbackq;
+ startp = stackblock() + startloc;
+
+ switch (subtype) {
+ case VSASSIGN:
+ setvar(str, startp, 0);
+ amount = startp - expdest;
+ STADJUST(amount, expdest);
+ return startp;
+
+ case VSQUESTION:
+ varunset(p, str, startp, varflags);
+ /* NOTREACHED */
+ }
+
+ subtype -= VSTRIMRIGHT;
+#ifdef DEBUG
+ if (subtype < 0 || subtype > 3)
+ abort();
+#endif
+
+ rmesc = startp;
+ rmescend = stackblock() + strloc;
+ if (quotes) {
+ rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+ if (rmesc != startp) {
+ rmescend = expdest;
+ startp = stackblock() + startloc;
+ }
+ }
+ rmescend--;
+ str = stackblock() + strloc;
+ preglob(str, 0);
+
+ /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
+ zero = subtype >> 1;
+ /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
+ scan = (subtype & 1) ^ zero ? scanleft : scanright;
+
+ loc = scan(startp, rmesc, rmescend, str, quotes, zero);
+ if (loc) {
+ if (zero) {
+ memmove(startp, loc, str - loc);
+ loc = startp + (str - loc) - 1;
+ }
+ *loc = '\0';
+ amount = loc - expdest;
+ STADJUST(amount, expdest);
+ }
+ return loc;
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+STATIC char *
+evalvar(char *p, int flag)
+{
+ int subtype;
+ int varflags;
+ char *var;
+ int patloc;
+ int c;
+ int startloc;
+ ssize_t varlen;
+ int easy;
+ int quoted;
+
+ varflags = *p++;
+ subtype = varflags & VSTYPE;
+
+ if (!subtype)
+ sh_error("Bad substitution");
+
+ quoted = flag & EXP_QUOTED;
+ var = p;
+ easy = (!quoted || (*var == '@' && shellparam.nparam));
+ startloc = expdest - (char *)stackblock();
+ p = strchr(p, '=') + 1;
+
+again:
+ varlen = varvalue(var, varflags, flag);
+ if (varflags & VSNUL)
+ varlen--;
+
+ if (subtype == VSPLUS) {
+ varlen = -1 - varlen;
+ goto vsplus;
+ }
+
+ if (subtype == VSMINUS) {
+vsplus:
+ if (varlen < 0) {
+ argstr(p, flag | EXP_TILDE | EXP_WORD);
+ goto end;
+ }
+ if (easy)
+ goto record;
+ goto end;
+ }
+
+ if (subtype == VSASSIGN || subtype == VSQUESTION) {
+ if (varlen < 0) {
+ if (subevalvar(p, var, 0, subtype, startloc,
+ varflags, flag & ~QUOTES_ESC)) {
+ varflags &= ~VSNUL;
+ /*
+ * Remove any recorded regions beyond
+ * start of variable
+ */
+ removerecordregions(startloc);
+ goto again;
+ }
+ goto end;
+ }
+ if (easy)
+ goto record;
+ goto end;
+ }
+
+ if (varlen < 0 && uflag)
+ varunset(p, var, 0, 0);
+
+ if (subtype == VSLENGTH) {
+ cvtnum(varlen > 0 ? varlen : 0);
+ goto record;
+ }
+
+ if (subtype == VSNORMAL) {
+ if (!easy)
+ goto end;
+record:
+ recordregion(startloc, expdest - (char *)stackblock(), quoted);
+ goto end;
+ }
+
+#ifdef DEBUG
+ switch (subtype) {
+ case VSTRIMLEFT:
+ case VSTRIMLEFTMAX:
+ case VSTRIMRIGHT:
+ case VSTRIMRIGHTMAX:
+ break;
+ default:
+ abort();
+ }
+#endif
+
+ if (varlen >= 0) {
+ /*
+ * Terminate the string and start recording the pattern
+ * right after it
+ */
+ STPUTC('\0', expdest);
+ patloc = expdest - (char *)stackblock();
+ if (subevalvar(p, NULL, patloc, subtype,
+ startloc, varflags, flag) == 0) {
+ int amount = expdest - (
+ (char *)stackblock() + patloc - 1
+ );
+ STADJUST(-amount, expdest);
+ }
+ /* Remove any recorded regions beyond start of variable */
+ removerecordregions(startloc);
+ goto record;
+ }
+
+end:
+ if (subtype != VSNORMAL) { /* skip to end of alternative */
+ int nesting = 1;
+ for (;;) {
+ if ((c = (signed char)*p++) == CTLESC)
+ p++;
+ else if (c == CTLBACKQ) {
+ if (varlen >= 0)
+ argbackq = argbackq->next;
+ } else if (c == CTLVAR) {
+ if ((*p++ & VSTYPE) != VSNORMAL)
+ nesting++;
+ } else if (c == CTLENDVAR) {
+ if (--nesting == 0)
+ break;
+ }
+ }
+ }
+ return p;
+}
+
+
+/*
+ * Put a string on the stack.
+ */
+
+STATIC void
+memtodest(const char *p, size_t len, const char *syntax, int quotes) {
+ char *q;
+
+ if (unlikely(!len))
+ return;
+
+ q = makestrspace(len * 2, expdest);
+
+ do {
+ int c = (signed char)*p++;
+ if (c) {
+ if ((quotes & QUOTES_ESC) &&
+ ((syntax[c] == CCTL) ||
+ (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
+ syntax[c] == CBACK)))
+ USTPUTC(CTLESC, q);
+ } else if (!(quotes & QUOTES_KEEPNUL))
+ continue;
+ USTPUTC(c, q);
+ } while (--len);
+
+ expdest = q;
+}
+
+
+STATIC size_t
+strtodest(p, syntax, quotes)
+ const char *p;
+ const char *syntax;
+ int quotes;
+{
+ size_t len = strlen(p);
+ memtodest(p, len, syntax, quotes);
+ return len;
+}
+
+
+
+/*
+ * Add the value of a specialized variable to the stack string.
+ */
+
+STATIC ssize_t
+varvalue(char *name, int varflags, int flags)
+{
+ int num;
+ char *p;
+ int i;
+ int sep;
+ char sepc;
+ char **ap;
+ char const *syntax;
+ int quoted = flags & EXP_QUOTED;
+ int subtype = varflags & VSTYPE;
+ int discard = subtype == VSPLUS || subtype == VSLENGTH;
+ int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
+ ssize_t len = 0;
+
+ sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+ syntax = quoted ? DQSYNTAX : BASESYNTAX;
+
+ switch (*name) {
+ case '$':
+ num = rootpid;
+ goto numvar;
+ case '?':
+ num = exitstatus;
+ goto numvar;
+ case '#':
+ num = shellparam.nparam;
+ goto numvar;
+ case '!':
+ num = backgndpid;
+ if (num == 0)
+ return -1;
+numvar:
+ len = cvtnum(num);
+ break;
+ case '-':
+ p = makestrspace(NOPTS, expdest);
+ for (i = NOPTS - 1; i >= 0; i--) {
+ if (optlist[i]) {
+ USTPUTC(optletters[i], p);
+ len++;
+ }
+ }
+ expdest = p;
+ break;
+ case '@':
+ if (sep)
+ goto param;
+ /* fall through */
+ case '*':
+ sep = ifsset() ? ifsval()[0] : ' ';
+param:
+ if (!(ap = shellparam.p))
+ return -1;
+ sepc = sep;
+ while ((p = *ap++)) {
+ len += strtodest(p, syntax, quotes);
+
+ if (*ap && sep) {
+ len++;
+ memtodest(&sepc, 1, syntax, quotes);
+ }
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ num = atoi(name);
+ if (num < 0 || num > shellparam.nparam)
+ return -1;
+ p = num ? shellparam.p[num - 1] : arg0;
+ goto value;
+ default:
+ p = lookupvar(name);
+value:
+ if (!p)
+ return -1;
+
+ len = strtodest(p, syntax, quotes);
+ break;
+ }
+
+ if (discard)
+ STADJUST(-len, expdest);
+ return len;
+}
+
+
+
+/*
+ * Record the fact that we have to scan this region of the
+ * string for IFS characters.
+ */
+
+void
+recordregion(int start, int end, int nulonly)
+{
+ struct ifsregion *ifsp;
+
+ if (ifslastp == NULL) {
+ ifsp = &ifsfirst;
+ } else {
+ INTOFF;
+ ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
+ ifsp->next = NULL;
+ ifslastp->next = ifsp;
+ INTON;
+ }
+ ifslastp = ifsp;
+ ifslastp->begoff = start;
+ ifslastp->endoff = end;
+ ifslastp->nulonly = nulonly;
+}
+
+
+
+/*
+ * Break the argument string into pieces based upon IFS and add the
+ * strings to the argument list. The regions of the string to be
+ * searched for IFS characters have been stored by recordregion.
+ */
+void
+ifsbreakup(char *string, struct arglist *arglist)
+{
+ struct ifsregion *ifsp;
+ struct strlist *sp;
+ char *start;
+ char *p;
+ char *q;
+ const char *ifs, *realifs;
+ int ifsspc;
+ int nulonly;
+
+
+ start = string;
+ if (ifslastp != NULL) {
+ ifsspc = 0;
+ nulonly = 0;
+ realifs = ifsset() ? ifsval() : defifs;
+ ifsp = &ifsfirst;
+ do {
+ p = string + ifsp->begoff;
+ nulonly = ifsp->nulonly;
+ ifs = nulonly ? nullstr : realifs;
+ ifsspc = 0;
+ while (p < string + ifsp->endoff) {
+ q = p;
+ if (*p == (char)CTLESC)
+ p++;
+ if (strchr(ifs, *p)) {
+ if (!nulonly)
+ ifsspc = (strchr(defifs, *p) != NULL);
+ /* Ignore IFS whitespace at start */
+ if (q == start && ifsspc) {
+ p++;
+ start = p;
+ continue;
+ }
+ *q = '\0';
+ sp = (struct strlist *)stalloc(sizeof *sp);
+ sp->text = start;
+ *arglist->lastp = sp;
+ arglist->lastp = &sp->next;
+ p++;
+ if (!nulonly) {
+ for (;;) {
+ if (p >= string + ifsp->endoff) {
+ break;
+ }
+ q = p;
+ if (*p == (char)CTLESC)
+ p++;
+ if (strchr(ifs, *p) == NULL ) {
+ p = q;
+ break;
+ } else if (strchr(defifs, *p) == NULL) {
+ if (ifsspc) {
+ p++;
+ ifsspc = 0;
+ } else {
+ p = q;
+ break;
+ }
+ } else
+ p++;
+ }
+ }
+ start = p;
+ } else
+ p++;
+ }
+ } while ((ifsp = ifsp->next) != NULL);
+ if (nulonly)
+ goto add;
+ }
+
+ if (!*start)
+ return;
+
+add:
+ sp = (struct strlist *)stalloc(sizeof *sp);
+ sp->text = start;
+ *arglist->lastp = sp;
+ arglist->lastp = &sp->next;
+}
+
+void ifsfree(void)
+{
+ struct ifsregion *p = ifsfirst.next;
+
+ if (!p)
+ goto out;
+
+ INTOFF;
+ do {
+ struct ifsregion *ifsp;
+ ifsp = p->next;
+ ckfree(p);
+ p = ifsp;
+ } while (p);
+ ifsfirst.next = NULL;
+ INTON;
+
+out:
+ ifslastp = NULL;
+}
+
+
+
+/*
+ * Expand shell metacharacters. At this point, the only control characters
+ * should be escapes. The results are stored in the list exparg.
+ */
+
+#ifdef HAVE_GLOB
+STATIC void
+expandmeta(str, flag)
+ struct strlist *str;
+ int flag;
+{
+ /* TODO - EXP_REDIR */
+
+ while (str) {
+ const char *p;
+ glob_t pglob;
+ int i;
+
+ if (fflag)
+ goto nometa;
+ INTOFF;
+ p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+ i = glob(p, GLOB_NOMAGIC, 0, &pglob);
+ if (p != str->text)
+ ckfree(p);
+ switch (i) {
+ case 0:
+ if (!(pglob.gl_flags & GLOB_MAGCHAR))
+ goto nometa2;
+ addglob(&pglob);
+ globfree(&pglob);
+ INTON;
+ break;
+ case GLOB_NOMATCH:
+nometa2:
+ globfree(&pglob);
+ INTON;
+nometa:
+ *exparg.lastp = str;
+ rmescapes(str->text);
+ exparg.lastp = &str->next;
+ break;
+ default: /* GLOB_NOSPACE */
+ sh_error("Out of space");
+ }
+ str = str->next;
+ }
+}
+
+
+/*
+ * Add the result of glob(3) to the list.
+ */
+
+STATIC void
+addglob(pglob)
+ const glob_t *pglob;
+{
+ char **p = pglob->gl_pathv;
+
+ do {
+ addfname(*p);
+ } while (*++p);
+}
+
+
+#else /* HAVE_GLOB */
+STATIC char *expdir;
+
+
+STATIC void
+expandmeta(struct strlist *str, int flag)
+{
+ static const char metachars[] = {
+ '*', '?', '[', 0
+ };
+ /* TODO - EXP_REDIR */
+
+ while (str) {
+ struct strlist **savelastp;
+ struct strlist *sp;
+ char *p;
+
+ if (fflag)
+ goto nometa;
+ if (!strpbrk(str->text, metachars))
+ goto nometa;
+ savelastp = exparg.lastp;
+
+ INTOFF;
+ p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+ {
+ int i = strlen(str->text);
+ expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
+ }
+
+ expmeta(expdir, p);
+ ckfree(expdir);
+ if (p != str->text)
+ ckfree(p);
+ INTON;
+ if (exparg.lastp == savelastp) {
+ /*
+ * no matches
+ */
+nometa:
+ *exparg.lastp = str;
+ rmescapes(str->text);
+ exparg.lastp = &str->next;
+ } else {
+ *exparg.lastp = NULL;
+ *savelastp = sp = expsort(*savelastp);
+ while (sp->next != NULL)
+ sp = sp->next;
+ exparg.lastp = &sp->next;
+ }
+ str = str->next;
+ }
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+STATIC void
+expmeta(char *enddir, char *name)
+{
+ char *p;
+ const char *cp;
+ char *start;
+ char *endname;
+ int metaflag;
+ struct stat64 statb;
+ DIR *dirp;
+ struct dirent *dp;
+ int atend;
+ int matchdot;
+ int esc;
+
+ metaflag = 0;
+ start = name;
+ for (p = name; esc = 0, *p; p += esc + 1) {
+ if (*p == '*' || *p == '?')
+ metaflag = 1;
+ else if (*p == '[') {
+ char *q = p + 1;
+ if (*q == '!')
+ q++;
+ for (;;) {
+ if (*q == '\\')
+ q++;
+ if (*q == '/' || *q == '\0')
+ break;
+ if (*++q == ']') {
+ metaflag = 1;
+ break;
+ }
+ }
+ } else {
+ if (*p == '\\')
+ esc++;
+ if (p[esc] == '/') {
+ if (metaflag)
+ break;
+ start = p + esc + 1;
+ }
+ }
+ }
+ if (metaflag == 0) { /* we've reached the end of the file name */
+ if (enddir != expdir)
+ metaflag++;
+ p = name;
+ do {
+ if (*p == '\\')
+ p++;
+ *enddir++ = *p;
+ } while (*p++);
+ if (metaflag == 0 || lstat64(expdir, &statb) >= 0)
+ addfname(expdir);
+ return;
+ }
+ endname = p;
+ if (name < start) {
+ p = name;
+ do {
+ if (*p == '\\')
+ p++;
+ *enddir++ = *p++;
+ } while (p < start);
+ }
+ if (enddir == expdir) {
+ cp = ".";
+ } else if (enddir == expdir + 1 && *expdir == '/') {
+ cp = "/";
+ } else {
+ cp = expdir;
+ enddir[-1] = '\0';
+ }
+ if ((dirp = opendir(cp)) == NULL)
+ return;
+ if (enddir != expdir)
+ enddir[-1] = '/';
+ if (*endname == 0) {
+ atend = 1;
+ } else {
+ atend = 0;
+ *endname = '\0';
+ endname += esc + 1;
+ }
+ matchdot = 0;
+ p = start;
+ if (*p == '\\')
+ p++;
+ if (*p == '.')
+ matchdot++;
+ while (! int_pending() && (dp = readdir(dirp)) != NULL) {
+ if (dp->d_name[0] == '.' && ! matchdot)
+ continue;
+ if (pmatch(start, dp->d_name)) {
+ if (atend) {
+ scopy(dp->d_name, enddir);
+ addfname(expdir);
+ } else {
+ for (p = enddir, cp = dp->d_name;
+ (*p++ = *cp++) != '\0';)
+ continue;
+ p[-1] = '/';
+ expmeta(p, endname);
+ }
+ }
+ }
+ closedir(dirp);
+ if (! atend)
+ endname[-esc - 1] = esc ? '\\' : '/';
+}
+#endif /* HAVE_GLOB */
+
+
+/*
+ * Add a file name to the list.
+ */
+
+STATIC void
+addfname(char *name)
+{
+ struct strlist *sp;
+
+ sp = (struct strlist *)stalloc(sizeof *sp);
+ sp->text = sstrdup(name);
+ *exparg.lastp = sp;
+ exparg.lastp = &sp->next;
+}
+
+
+#ifndef HAVE_GLOB
+/*
+ * Sort the results of file name expansion. It calculates the number of
+ * strings to sort and then calls msort (short for merge sort) to do the
+ * work.
+ */
+
+STATIC struct strlist *
+expsort(struct strlist *str)
+{
+ int len;
+ struct strlist *sp;
+
+ len = 0;
+ for (sp = str ; sp ; sp = sp->next)
+ len++;
+ return msort(str, len);
+}
+
+
+STATIC struct strlist *
+msort(struct strlist *list, int len)
+{
+ struct strlist *p, *q = NULL;
+ struct strlist **lpp;
+ int half;
+ int n;
+
+ if (len <= 1)
+ return list;
+ half = len >> 1;
+ p = list;
+ for (n = half ; --n >= 0 ; ) {
+ q = p;
+ p = p->next;
+ }
+ q->next = NULL; /* terminate first half of list */
+ q = msort(list, half); /* sort first half of list */
+ p = msort(p, len - half); /* sort second half */
+ lpp = &list;
+ for (;;) {
+ if (strcmp(p->text, q->text) < 0) {
+ *lpp = p;
+ lpp = &p->next;
+ if ((p = *lpp) == NULL) {
+ *lpp = q;
+ break;
+ }
+ } else {
+ *lpp = q;
+ lpp = &q->next;
+ if ((q = *lpp) == NULL) {
+ *lpp = p;
+ break;
+ }
+ }
+ }
+ return list;
+}
+#endif
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+STATIC inline int
+patmatch(char *pattern, const char *string)
+{
+ return pmatch(preglob(pattern, 0), string);
+}
+
+
+#ifndef HAVE_FNMATCH
+STATIC int ccmatch(const char *p, int chr, const char **r)
+{
+ static const struct class {
+ char name[10];
+ int (*fn)(int);
+ } classes[] = {
+ { .name = ":alnum:]", .fn = isalnum },
+ { .name = ":cntrl:]", .fn = iscntrl },
+ { .name = ":lower:]", .fn = islower },
+ { .name = ":space:]", .fn = isspace },
+ { .name = ":alpha:]", .fn = isalpha },
+ { .name = ":digit:]", .fn = isdigit },
+ { .name = ":print:]", .fn = isprint },
+ { .name = ":upper:]", .fn = isupper },
+ { .name = ":blank:]", .fn = isblank },
+ { .name = ":graph:]", .fn = isgraph },
+ { .name = ":punct:]", .fn = ispunct },
+ { .name = ":xdigit:]", .fn = isxdigit },
+ };
+ const struct class *class, *end;
+
+ end = classes + sizeof(classes) / sizeof(classes[0]);
+ for (class = classes; class < end; class++) {
+ const char *q;
+
+ q = prefix(p, class->name);
+ if (!q)
+ continue;
+ *r = q;
+ return class->fn(chr);
+ }
+
+ *r = 0;
+ return 0;
+}
+
+STATIC int
+pmatch(const char *pattern, const char *string)
+{
+ const char *p, *q;
+ char c;
+
+ p = pattern;
+ q = string;
+ for (;;) {
+ switch (c = *p++) {
+ case '\0':
+ goto breakloop;
+ case '\\':
+ if (*p) {
+ c = *p++;
+ }
+ goto dft;
+ case '?':
+ if (*q++ == '\0')
+ return 0;
+ break;
+ case '*':
+ c = *p;
+ while (c == '*')
+ c = *++p;
+ if (c != '\\' && c != '?' && c != '*' && c != '[') {
+ while (*q != c) {
+ if (*q == '\0')
+ return 0;
+ q++;
+ }
+ }
+ do {
+ if (pmatch(p, q))
+ return 1;
+ } while (*q++ != '\0');
+ return 0;
+ case '[': {
+ const char *startp;
+ int invert, found;
+ char chr;
+
+ startp = p;
+ invert = 0;
+ if (*p == '!') {
+ invert++;
+ p++;
+ }
+ found = 0;
+ chr = *q++;
+ if (chr == '\0')
+ return 0;
+ c = *p++;
+ do {
+ if (!c) {
+ p = startp;
+ c = *p;
+ goto dft;
+ }
+ if (c == '[') {
+ const char *r;
+
+ found |= !!ccmatch(p, chr, &r);
+ if (r) {
+ p = r;
+ continue;
+ }
+ } else if (c == '\\')
+ c = *p++;
+ if (*p == '-' && p[1] != ']') {
+ p++;
+ if (*p == '\\')
+ p++;
+ if (chr >= c && chr <= *p)
+ found = 1;
+ p++;
+ } else {
+ if (chr == c)
+ found = 1;
+ }
+ } while ((c = *p++) != ']');
+ if (found == invert)
+ return 0;
+ break;
+ }
+dft: default:
+ if (*q++ != c)
+ return 0;
+ break;
+ }
+ }
+breakloop:
+ if (*q != '\0')
+ return 0;
+ return 1;
+}
+#endif
+
+
+
+/*
+ * Remove any CTLESC characters from a string.
+ */
+
+char *
+_rmescapes(char *str, int flag)
+{
+ char *p, *q, *r;
+ unsigned inquotes;
+ int notescaped;
+ int globbing;
+
+ p = strpbrk(str, qchars);
+ if (!p) {
+ return str;
+ }
+ q = p;
+ r = str;
+ if (flag & RMESCAPE_ALLOC) {
+ size_t len = p - str;
+ size_t fulllen = len + strlen(p) + 1;
+
+ if (flag & RMESCAPE_GROW) {
+ int strloc = str - (char *)stackblock();
+
+ r = makestrspace(fulllen, expdest);
+ str = (char *)stackblock() + strloc;
+ p = str + len;
+ } else if (flag & RMESCAPE_HEAP) {
+ r = ckmalloc(fulllen);
+ } else {
+ r = stalloc(fulllen);
+ }
+ q = r;
+ if (len > 0) {
+ q = mempcpy(q, str, len);
+ }
+ }
+ inquotes = 0;
+ globbing = flag & RMESCAPE_GLOB;
+ notescaped = globbing;
+ while (*p) {
+ if (*p == (char)CTLQUOTEMARK) {
+ inquotes = ~inquotes;
+ p++;
+ notescaped = globbing;
+ continue;
+ }
+ if (*p == (char)CTLESC) {
+ p++;
+ if (notescaped)
+ *q++ = '\\';
+ } else if (*p == '\\' && !inquotes) {
+ /* naked back slash */
+ notescaped = 0;
+ goto copy;
+ }
+ notescaped = globbing;
+copy:
+ *q++ = *p++;
+ }
+ *q = '\0';
+ if (flag & RMESCAPE_GROW) {
+ expdest = r;
+ STADJUST(q - r + 1, expdest);
+ }
+ return r;
+}
+
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, char *val)
+{
+ struct stackmark smark;
+ int result;
+
+ setstackmark(&smark);
+ argbackq = pattern->narg.backquote;
+ STARTSTACKSTR(expdest);
+ argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
+ STACKSTRNUL(expdest);
+ ifsfree();
+ result = patmatch(stackblock(), val);
+ popstackmark(&smark);
+ return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+STATIC int
+cvtnum(intmax_t num)
+{
+ int len = max_int_length(sizeof(num));
+
+ expdest = makestrspace(len, expdest);
+ len = fmtstr(expdest, len, "%" PRIdMAX, num);
+ STADJUST(len, expdest);
+ return len;
+}
+
+STATIC void
+varunset(const char *end, const char *var, const char *umsg, int varflags)
+{
+ const char *msg;
+ const char *tail;
+
+ tail = nullstr;
+ msg = "parameter not set";
+ if (umsg) {
+ if (*end == (char)CTLENDVAR) {
+ if (varflags & VSNUL)
+ tail = " or null";
+ } else
+ msg = umsg;
+ }
+ sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
+}
+
+#ifdef mkinit
+
+INCLUDE "expand.h"
+
+RESET {
+ ifsfree();
+}
+
+#endif
diff --git a/usr/dash/expand.h b/usr/dash/expand.h
new file mode 100644
index 0000000..9cf1276
--- /dev/null
+++ b/usr/dash/expand.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)expand.h 8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef DASH_STRLIST_H
+#define DASH_STRLIST_H
+
+#include <inttypes.h>
+
+struct strlist {
+ struct strlist *next;
+ char *text;
+};
+
+
+struct arglist {
+ struct strlist *list;
+ struct strlist **lastp;
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_FULL 0x1 /* perform word splitting & file globbing */
+#define EXP_TILDE 0x2 /* do normal tilde expansion */
+#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
+#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
+#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
+#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
+#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
+#define EXP_WORD 0x80 /* expand word in parameter expansion */
+#define EXP_QUOTED 0x100 /* expand word in double quotes */
+
+
+union node;
+void expandarg(union node *, struct arglist *, int);
+void expari(int);
+#define rmescapes(p) _rmescapes((p), 0)
+char *_rmescapes(char *, int);
+int casematch(union node *, char *);
+void recordregion(int, int, int);
+void removerecordregions(int);
+void ifsbreakup(char *, struct arglist *);
+void ifsfree(void);
+
+/* From arith.y */
+intmax_t arith(const char *);
+int expcmd(int , char **);
+#ifdef USE_LEX
+void arith_lex_reset(void);
+#else
+#define arith_lex_reset()
+#endif
+int yylex(void);
+
+#endif /* DASH_STRLIST_H */
diff --git a/usr/dash/funcs/cmv b/usr/dash/funcs/cmv
new file mode 100644
index 0000000..91a67c5
--- /dev/null
+++ b/usr/dash/funcs/cmv
@@ -0,0 +1,47 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)cmv 8.2 (Berkeley) 5/4/95
+
+# Conditional move--don't replace an existing file.
+
+cmv() {
+ if test $# != 2
+ then echo "cmv: arg count"
+ return 2
+ fi
+ if test -f "$2" -o -w "$2"
+ then echo "$2 exists"
+ return 2
+ fi
+ /bin/mv "$1" "$2"
+}
diff --git a/usr/dash/funcs/dirs b/usr/dash/funcs/dirs
new file mode 100644
index 0000000..7d840eb
--- /dev/null
+++ b/usr/dash/funcs/dirs
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)dirs 8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/usr/dash/funcs/kill b/usr/dash/funcs/kill
new file mode 100644
index 0000000..c5df95f
--- /dev/null
+++ b/usr/dash/funcs/kill
@@ -0,0 +1,47 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (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 8.2 (Berkeley) 5/4/95
+
+# Convert job names to process ids and then run /bin/kill.
+
+kill() {
+ local args x
+ args=
+ for x in "$@"
+ do case $x in
+ %*) x=`jobid "$x"` ;;
+ esac
+ args="$args $x"
+ done
+ /bin/kill $args
+}
diff --git a/usr/dash/funcs/login b/usr/dash/funcs/login
new file mode 100644
index 0000000..215e535
--- /dev/null
+++ b/usr/dash/funcs/login
@@ -0,0 +1,36 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)login 8.2 (Berkeley) 5/4/95
+
+# replaces the login builtin in the BSD shell
+login () exec login "$@"
diff --git a/usr/dash/funcs/newgrp b/usr/dash/funcs/newgrp
new file mode 100644
index 0000000..ec0e7e5
--- /dev/null
+++ b/usr/dash/funcs/newgrp
@@ -0,0 +1,35 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)newgrp 8.2 (Berkeley) 5/4/95
+
+newgrp() exec newgrp "$@"
diff --git a/usr/dash/funcs/popd b/usr/dash/funcs/popd
new file mode 100644
index 0000000..3b1ab46
--- /dev/null
+++ b/usr/dash/funcs/popd
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)popd 8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/usr/dash/funcs/pushd b/usr/dash/funcs/pushd
new file mode 100644
index 0000000..483d358
--- /dev/null
+++ b/usr/dash/funcs/pushd
@@ -0,0 +1,71 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)pushd 8.2 (Berkeley) 5/4/95
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/usr/dash/funcs/suspend b/usr/dash/funcs/suspend
new file mode 100644
index 0000000..4484467
--- /dev/null
+++ b/usr/dash/funcs/suspend
@@ -0,0 +1,39 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)suspend 8.2 (Berkeley) 5/4/95
+
+suspend() {
+ local -
+ set +j
+ kill -TSTP 0
+}
diff --git a/usr/dash/gendeps.pl b/usr/dash/gendeps.pl
new file mode 100755
index 0000000..e6797de
--- /dev/null
+++ b/usr/dash/gendeps.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# Generate dependencies for *generated* header files. Generated
+# header files have to use #include "foo.h" syntax.
+#
+
+($src, $obj, @build_headers) = @ARGV;
+%build_headers = map { $_ => 1 } @build_headers;
+
+open(GENDEPS, "> $obj/.gendeps\0")
+ or die "$0: Cannot create $obj/.gendeps: $!\n";
+
+opendir(DIR, $src) or die "$0: Cannot opendir $src: $!\n";
+while ( defined($file = readdir(DIR)) ) {
+ if ( $file =~ /^(.*)\.c$/ ) {
+ $basename = $1;
+ @hdrs = ();
+ open(FILE, "< $src/$file\0")
+ or die "$0: Cannot open $src/$file: $!\n";
+ while ( defined($line = <FILE>) ) {
+ if ( $line =~ /^\s*\#\s*include\s+\"(.*)\"/ ) {
+ $header = $1;
+
+ if ( $build_headers{$header} ) {
+ push(@hdrs, "\$(obj)/$header");
+ }
+ }
+ }
+ close(FILE);
+
+ if (scalar(@hdrs)) {
+ print GENDEPS "\$(obj)/$basename.o: ", join(' ', @hdrs), "\n";
+ }
+ }
+}
+
+closedir(DIR);
+close(GENDEPS);
diff --git a/usr/dash/hetio.c b/usr/dash/hetio.c
new file mode 100644
index 0000000..f7d175f
--- /dev/null
+++ b/usr/dash/hetio.c
@@ -0,0 +1,397 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
+ * Etc: Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5 19990328 Initial release
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+/*
+Usage and Known bugs:
+ Terminal key codes are not extensive, and more will probably
+ need to be added. This version was created on Debian GNU/Linux 2.x.
+ Delete, Backspace, Home, End, and the arrow keys were tested
+ to work in an Xterm and console. Ctrl-A also works as Home.
+ Ctrl-E also works as End. Ctrl-D and Ctrl-U perform their respective
+ functions. The binary size increase is <3K.
+
+ Editting will not display correctly for lines greater then the
+ terminal width. (more then one line.) However, history will.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+
+#include "input.h"
+#include "output.h"
+
+#include "hetio.h"
+
+
+#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */
+
+#define ESC 27
+#define DEL 127
+
+static struct history *his_front = NULL; /* First element in command line list */
+static struct history *his_end = NULL; /* Last element in command line list */
+static struct termios old_term, new_term; /* Current termio and the previous termio before starting ash */
+
+static int history_counter = 0; /* Number of commands in history list */
+static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */
+static int hetio_inter = 0;
+
+struct history
+{
+ char *s;
+ struct history *p;
+ struct history *n;
+};
+
+
+void input_delete (int);
+void input_home (int *);
+void input_end (int *, int);
+void input_backspace (int *, int *);
+
+
+
+void hetio_init(void)
+{
+ hetio_inter = 1;
+}
+
+
+void hetio_reset_term(void)
+{
+ if (reset_term)
+ tcsetattr(1, TCSANOW, &old_term);
+}
+
+
+void setIO(struct termios *new, struct termios *old) /* Set terminal IO to canonical mode, and save old term settings. */
+{
+ tcgetattr(0, old);
+ memcpy(new, old, sizeof(*new));
+ new->c_cc[VMIN] = 1;
+ new->c_cc[VTIME] = 0;
+ new->c_lflag &= ~ICANON; /* unbuffered input */
+ new->c_lflag &= ~ECHO;
+ tcsetattr(0, TCSANOW, new);
+}
+
+void input_home(int *cursor) /* Command line input routines */
+{
+ while (*cursor > 0) {
+ out1c('\b');
+ --*cursor;
+ }
+ flushout(out1);
+}
+
+
+void input_delete(int cursor)
+{
+ int j = 0;
+
+ memmove(parsenextc + cursor, parsenextc + cursor + 1,
+ BUFSIZ - cursor - 1);
+ for (j = cursor; j < (BUFSIZ - 1); j++) {
+ if (!*(parsenextc + j))
+ break;
+ else
+ out1c(*(parsenextc + j));
+ }
+
+ out1str(" \b");
+
+ while (j-- > cursor)
+ out1c('\b');
+ flushout(out1);
+}
+
+
+void input_end(int *cursor, int len)
+{
+ while (*cursor < len) {
+ out1str("\033[C");
+ ++*cursor;
+ }
+ flushout(out1);
+}
+
+
+void
+input_backspace(int *cursor, int *len)
+{
+ int j = 0;
+
+ if (*cursor > 0) {
+ out1str("\b \b");
+ --*cursor;
+ memmove(parsenextc + *cursor, parsenextc + *cursor + 1,
+ BUFSIZ - *cursor + 1);
+
+ for (j = *cursor; j < (BUFSIZ - 1); j++) {
+ if (!*(parsenextc + j))
+ break;
+ else
+ out1c(*(parsenextc + j));
+ }
+
+ out1str(" \b");
+
+ while (j-- > *cursor)
+ out1c('\b');
+
+ --*len;
+ flushout(out1);
+ }
+}
+
+int hetio_read_input(int fd)
+{
+ int nr = 0;
+
+ /* Are we an interactive shell? */
+ if (!hetio_inter || fd) {
+ return -255;
+ } else {
+ int len = 0;
+ int j = 0;
+ int cursor = 0;
+ int break_out = 0;
+ int ret = 0;
+ char c = 0;
+ struct history *hp = his_end;
+
+ if (!reset_term) {
+ setIO(&new_term, &old_term);
+ reset_term = 1;
+ } else {
+ tcsetattr(0, TCSANOW, &new_term);
+ }
+
+ memset(parsenextc, 0, BUFSIZ);
+
+ while (1) {
+ if ((ret = read(fd, &c, 1)) < 1)
+ return ret;
+
+ switch (c) {
+ case 1: /* Control-A Beginning of line */
+ input_home(&cursor);
+ break;
+ case 5: /* Control-E EOL */
+ input_end(&cursor, len);
+ break;
+ case 4: /* Control-D */
+ if (!len)
+ exitshell(0);
+ break;
+ case 21: /* Control-U */
+ /* Return to begining of line. */
+ for (; cursor > 0; cursor--)
+ out1c('\b');
+ /* Erase old command. */
+ for (j = 0; j < len; j++) {
+ /*
+ * Clear buffer while we're at
+ * it.
+ */
+ parsenextc[j] = 0;
+ out1c(' ');
+ }
+ /* return to begining of line */
+ for (; len > 0; len--)
+ out1c('\b');
+ flushout(out1);
+ break;
+ case '\b': /* Backspace */
+ case DEL:
+ input_backspace(&cursor, &len);
+ break;
+ case '\n': /* Enter */
+ *(parsenextc + len++ + 1) = c;
+ out1c(c);
+ flushout(out1);
+ break_out = 1;
+ break;
+ case ESC: /* escape sequence follows */
+ if ((ret = read(fd, &c, 1)) < 1)
+ return ret;
+
+ if (c == '[' ) { /* 91 */
+ if ((ret = read(fd, &c, 1)) < 1)
+ return ret;
+
+ switch (c) {
+ case 'A':
+ if (hp && hp->p) { /* Up */
+ hp = hp->p;
+ goto hop;
+ }
+ break;
+ case 'B':
+ if (hp && hp->n && hp->n->s) { /* Down */
+ hp = hp->n;
+ goto hop;
+ }
+ break;
+
+hop: /* hop */
+ len = strlen(parsenextc);
+
+ for (; cursor > 0; cursor--) /* return to begining of line */
+ out1c('\b');
+
+ for (j = 0; j < len; j++) /* erase old command */
+ out1c(' ');
+
+ for (; j > 0; j--) /* return to begining of line */
+ out1c('\b');
+
+ strcpy (parsenextc, hp->s); /* write new command */
+ len = strlen (hp->s);
+ out1str(parsenextc);
+ flushout(out1);
+ cursor = len;
+ break;
+ case 'C': /* Right */
+ if (cursor < len) {
+ out1str("\033[C");
+ cursor++;
+ flushout(out1);
+ }
+ break;
+ case 'D': /* Left */
+ if (cursor > 0) {
+ out1str("\033[D");
+ cursor--;
+ flushout(out1);
+ }
+ break;
+ case '3': /* Delete */
+ if (cursor != len) {
+ input_delete(cursor);
+ len--;
+ }
+ break;
+ case '1': /* Home (Ctrl-A) */
+ input_home(&cursor);
+ break;
+ case '4': /* End (Ctrl-E) */
+ input_end(&cursor, len);
+ break;
+ }
+ if (c == '1' || c == '3' || c == '4')
+ if ((ret = read(fd, &c, 1)) < 1)
+ return ret; /* read 126 (~) */
+ }
+
+ if (c == 'O') { /* 79 */
+ if ((ret = read(fd, &c, 1)) < 1)
+ return ret;
+ switch (c) {
+ case 'H': /* Home (xterm) */
+ input_home(&cursor);
+ break;
+ case 'F': /* End (xterm_ */
+ input_end(&cursor, len);
+ break;
+ }
+ }
+
+ c = 0;
+ break;
+
+ default: /* If it's regular input, do the normal thing */
+ if (!isprint(c)) /* Skip non-printable characters */
+ break;
+
+ if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */
+ break;
+
+ len++;
+
+ if (cursor == (len - 1)) { /* Append if at the end of the line */
+ *(parsenextc + cursor) = c;
+ } else { /* Insert otherwise */
+ memmove(parsenextc + cursor + 1, parsenextc + cursor,
+ len - cursor - 1);
+
+ *(parsenextc + cursor) = c;
+
+ for (j = cursor; j < len; j++)
+ out1c(*(parsenextc + j));
+ for (; j > cursor; j--)
+ out1str("\033[D");
+ }
+
+ cursor++;
+ out1c(c);
+ flushout(out1);
+ break;
+ }
+
+ if (break_out) /* Enter is the command terminator, no more input. */
+ break;
+ }
+
+ nr = len + 1;
+ tcsetattr(0, TCSANOW, &old_term);
+
+ if (*(parsenextc)) { /* Handle command history log */
+ struct history *h = his_end;
+
+ if (!h) { /* No previous history */
+ h = his_front = malloc(sizeof (struct history));
+ h->n = malloc(sizeof (struct history));
+ h->p = NULL;
+ h->s = strdup(parsenextc);
+
+ h->n->p = h;
+ h->n->n = NULL;
+ h->n->s = NULL;
+ his_end = h->n;
+ history_counter++;
+ } else { /* Add a new history command */
+
+ h->n = malloc(sizeof (struct history));
+
+ h->n->p = h;
+ h->n->n = NULL;
+ h->n->s = NULL;
+ h->s = strdup(parsenextc);
+ his_end = h->n;
+
+ if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */
+ struct history *p = his_front->n;
+
+ p->p = NULL;
+ free(his_front->s);
+ free(his_front);
+ his_front = p;
+ } else {
+ history_counter++;
+ }
+ }
+ }
+ }
+
+ return nr;
+}
diff --git a/usr/dash/hetio.h b/usr/dash/hetio.h
new file mode 100644
index 0000000..5f49713
--- /dev/null
+++ b/usr/dash/hetio.h
@@ -0,0 +1,22 @@
+/*
+ * Termios command line History and Editting for NetBSD sh (ash)
+ * Copyright (c) 1999
+ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
+ * Etc: Dave Cinege <dcinege@psychosis.com>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ *
+ * v 0.5 19990328 Initial release
+ *
+ * Future plans: Simple file and path name completion. (like BASH)
+ *
+ */
+
+void hetio_init(void);
+int hetio_read_input(int fd);
+void hetio_reset_term(void);
+
+extern int hetio_inter;
diff --git a/usr/dash/histedit.c b/usr/dash/histedit.c
new file mode 100644
index 0000000..b27d629
--- /dev/null
+++ b/usr/dash/histedit.c
@@ -0,0 +1,494 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE 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>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#include "error.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#include "eval.h"
+#include "memalloc.h"
+
+#define MAXHISTLOOPS 4 /* max recursions through fc */
+#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
+
+History *hist; /* history cookie */
+EditLine *el; /* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out;
+
+STATIC const char *fc_replace(const char *, char *, char *);
+
+#ifdef DEBUG
+extern FILE *tracefile;
+#endif
+
+/*
+ * Set history and editing status. Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+ FILE *el_err;
+
+#define editing (Eflag || Vflag)
+
+ if (iflag) {
+ if (!hist) {
+ /*
+ * turn history on
+ */
+ INTOFF;
+ hist = history_init();
+ INTON;
+
+ if (hist != NULL)
+ sethistsize(histsizeval());
+ else
+ out2str("sh: can't initialize history\n");
+ }
+ if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+ /*
+ * turn editing on
+ */
+ INTOFF;
+ if (el_in == NULL)
+ el_in = fdopen(0, "r");
+ if (el_out == NULL)
+ el_out = fdopen(2, "w");
+ if (el_in == NULL || el_out == NULL)
+ goto bad;
+ el_err = el_out;
+#if DEBUG
+ if (tracefile)
+ el_err = tracefile;
+#endif
+ el = el_init(arg0, el_in, el_out, el_err);
+ if (el != NULL) {
+ if (hist)
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_PROMPT, getprompt);
+ } else {
+bad:
+ out2str("sh: can't initialize editing\n");
+ }
+ INTON;
+ } else if (!editing && el) {
+ INTOFF;
+ el_end(el);
+ el = NULL;
+ INTON;
+ }
+ if (el) {
+ if (Vflag)
+ el_set(el, EL_EDITOR, "vi");
+ else if (Eflag)
+ el_set(el, EL_EDITOR, "emacs");
+ el_source(el, NULL);
+ }
+ } else {
+ INTOFF;
+ if (el) { /* no editing if not interactive */
+ el_end(el);
+ el = NULL;
+ }
+ if (hist) {
+ history_end(hist);
+ hist = NULL;
+ }
+ INTON;
+ }
+}
+
+
+void
+sethistsize(const char *hs)
+{
+ int histsize;
+ HistEvent he;
+
+ if (hist != NULL) {
+ if (hs == NULL || *hs == '\0' ||
+ (histsize = atoi(hs)) < 0)
+ histsize = 100;
+ history(hist, &he, H_SETSIZE, histsize);
+ }
+}
+
+void
+setterm(const char *term)
+{
+ if (el != NULL && term != NULL)
+ if (el_set(el, EL_TERMINAL, term) != 0) {
+ outfmt(out2, "sh: Can't set terminal type %s\n", term);
+ outfmt(out2, "sh: Using dumb terminal settings.\n");
+ }
+}
+
+/*
+ * This command is provided since POSIX decided to standardize
+ * the Korn shell fc command. Oh well...
+ */
+int
+histcmd(int argc, char **argv)
+{
+ int ch;
+ const char *editor = NULL;
+ HistEvent he;
+ int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+ int i, retval;
+ const char *firststr, *laststr;
+ int first, last, direction;
+ char *pat = NULL, *repl; /* ksh "fc old=new" crap */
+ static int active = 0;
+ struct jmploc jmploc;
+ struct jmploc *volatile savehandler;
+ char editfile[MAXPATHLEN + 1];
+ FILE *efp;
+#ifdef __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &editor;
+ (void) &lflg;
+ (void) &nflg;
+ (void) &rflg;
+ (void) &sflg;
+ (void) &firststr;
+ (void) &laststr;
+ (void) &pat;
+ (void) &repl;
+ (void) &efp;
+ (void) &argc;
+ (void) &argv;
+#endif
+
+ if (hist == NULL)
+ sh_error("history not active");
+
+ if (argc == 1)
+ sh_error("missing history argument");
+
+#ifdef __GLIBC__
+ optind = 0;
+#else
+ optreset = 1; optind = 1; /* initialize getopt */
+#endif
+ while (not_fcnumber(argv[optind]) &&
+ (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+ switch ((char)ch) {
+ case 'e':
+ editor = optionarg;
+ break;
+ case 'l':
+ lflg = 1;
+ break;
+ case 'n':
+ nflg = 1;
+ break;
+ case 'r':
+ rflg = 1;
+ break;
+ case 's':
+ sflg = 1;
+ break;
+ case ':':
+ sh_error("option -%c expects argument", optopt);
+ /* NOTREACHED */
+ case '?':
+ default:
+ sh_error("unknown option: -%c", optopt);
+ /* NOTREACHED */
+ }
+ argc -= optind, argv += optind;
+
+ /*
+ * If executing...
+ */
+ if (lflg == 0 || editor || sflg) {
+ lflg = 0; /* ignore */
+ editfile[0] = '\0';
+ /*
+ * Catch interrupts to reset active counter and
+ * cleanup temp files.
+ */
+ if (setjmp(jmploc.loc)) {
+ active = 0;
+ if (*editfile)
+ unlink(editfile);
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ savehandler = handler;
+ handler = &jmploc;
+ if (++active > MAXHISTLOOPS) {
+ active = 0;
+ displayhist = 0;
+ sh_error("called recursively too many times");
+ }
+ /*
+ * Set editor.
+ */
+ if (sflg == 0) {
+ if (editor == NULL &&
+ (editor = bltinlookup("FCEDIT")) == NULL &&
+ (editor = bltinlookup("EDITOR")) == NULL)
+ editor = DEFEDITOR;
+ if (editor[0] == '-' && editor[1] == '\0') {
+ sflg = 1; /* no edit */
+ editor = NULL;
+ }
+ }
+ }
+
+ /*
+ * If executing, parse [old=new] now
+ */
+ if (lflg == 0 && argc > 0 &&
+ ((repl = strchr(argv[0], '=')) != NULL)) {
+ pat = argv[0];
+ *repl++ = '\0';
+ argc--, argv++;
+ }
+ /*
+ * determine [first] and [last]
+ */
+ switch (argc) {
+ case 0:
+ firststr = lflg ? "-16" : "-1";
+ laststr = "-1";
+ break;
+ case 1:
+ firststr = argv[0];
+ laststr = lflg ? "-1" : argv[0];
+ break;
+ case 2:
+ firststr = argv[0];
+ laststr = argv[1];
+ break;
+ default:
+ sh_error("too many args");
+ /* NOTREACHED */
+ }
+ /*
+ * Turn into event numbers.
+ */
+ first = str_to_event(firststr, 0);
+ last = str_to_event(laststr, 1);
+
+ if (rflg) {
+ i = last;
+ last = first;
+ first = i;
+ }
+ /*
+ * XXX - this should not depend on the event numbers
+ * always increasing. Add sequence numbers or offset
+ * to the history element in next (diskbased) release.
+ */
+ direction = first < last ? H_PREV : H_NEXT;
+
+ /*
+ * If editing, grab a temp file.
+ */
+ if (editor) {
+ int fd;
+ INTOFF; /* easier */
+ sprintf(editfile, "%s_shXXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(editfile)) < 0)
+ sh_error("can't create temporary file %s", editfile);
+ if ((efp = fdopen(fd, "w")) == NULL) {
+ close(fd);
+ sh_error("can't allocate stdio buffer for temp");
+ }
+ }
+
+ /*
+ * Loop through selected history events. If listing or executing,
+ * do it now. Otherwise, put into temp file and call the editor
+ * after.
+ *
+ * The history interface needs rethinking, as the following
+ * convolutions will demonstrate.
+ */
+ history(hist, &he, H_FIRST);
+ retval = history(hist, &he, H_NEXT_EVENT, first);
+ for (;retval != -1; retval = history(hist, &he, direction)) {
+ if (lflg) {
+ if (!nflg)
+ out1fmt("%5d ", he.num);
+ out1str(he.str);
+ } else {
+ const char *s = pat ?
+ fc_replace(he.str, pat, repl) : he.str;
+
+ if (sflg) {
+ if (displayhist) {
+ out2str(s);
+ }
+
+ evalstring(strcpy(stalloc(strlen(s) + 1), s),
+ 0);
+ if (displayhist && hist) {
+ /*
+ * XXX what about recursive and
+ * relative histnums.
+ */
+ history(hist, &he, H_ENTER, s);
+ }
+ } else
+ fputs(s, efp);
+ }
+ /*
+ * At end? (if we were to lose last, we'd sure be
+ * messed up).
+ */
+ if (he.num == last)
+ break;
+ }
+ if (editor) {
+ char *editcmd;
+
+ fclose(efp);
+ editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+ sprintf(editcmd, "%s %s", editor, editfile);
+ /* XXX - should use no JC command */
+ evalstring(editcmd, 0);
+ INTON;
+ readcmdfile(editfile); /* XXX - should read back - quick tst */
+ unlink(editfile);
+ }
+
+ if (lflg == 0 && active > 0)
+ --active;
+ if (displayhist)
+ displayhist = 0;
+ return 0;
+}
+
+STATIC const char *
+fc_replace(const char *s, char *p, char *r)
+{
+ char *dest;
+ int plen = strlen(p);
+
+ STARTSTACKSTR(dest);
+ while (*s) {
+ if (*s == *p && strncmp(s, p, plen) == 0) {
+ while (*r)
+ STPUTC(*r++, dest);
+ s += plen;
+ *p = '\0'; /* so no more matches */
+ } else
+ STPUTC(*s++, dest);
+ }
+ STACKSTRNUL(dest);
+ dest = grabstackstr(dest);
+
+ return (dest);
+}
+
+int
+not_fcnumber(char *s)
+{
+ if (s == NULL)
+ return 0;
+ if (*s == '-')
+ s++;
+ return (!is_number(s));
+}
+
+int
+str_to_event(const char *str, int last)
+{
+ HistEvent he;
+ const char *s = str;
+ int relative = 0;
+ int i, retval;
+
+ retval = history(hist, &he, H_FIRST);
+ switch (*s) {
+ case '-':
+ relative = 1;
+ /*FALLTHROUGH*/
+ case '+':
+ s++;
+ }
+ if (is_number(s)) {
+ i = atoi(s);
+ if (relative) {
+ while (retval != -1 && i--) {
+ retval = history(hist, &he, H_NEXT);
+ }
+ if (retval == -1)
+ retval = history(hist, &he, H_LAST);
+ } else {
+ retval = history(hist, &he, H_NEXT_EVENT, i);
+ if (retval == -1) {
+ /*
+ * the notion of first and last is
+ * backwards to that of the history package
+ */
+ retval = history(hist, &he,
+ last ? H_FIRST : H_LAST);
+ }
+ }
+ if (retval == -1)
+ sh_error("history number %s not found (internal error)",
+ str);
+ } else {
+ /*
+ * pattern
+ */
+ retval = history(hist, &he, H_PREV_STR, str);
+ if (retval == -1)
+ sh_error("history pattern not found: %s", str);
+ }
+ return (he.num);
+}
+#endif
diff --git a/usr/dash/init.h b/usr/dash/init.h
new file mode 100644
index 0000000..e026e86
--- /dev/null
+++ b/usr/dash/init.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)init.h 8.2 (Berkeley) 5/4/95
+ */
+
+void init(void);
+void reset(void);
+void initshellproc(void);
diff --git a/usr/dash/input.c b/usr/dash/input.c
new file mode 100644
index 0000000..d31c45b
--- /dev/null
+++ b/usr/dash/input.c
@@ -0,0 +1,532 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "eval.h"
+#include "shell.h"
+#include "redir.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "options.h"
+#include "memalloc.h"
+#include "error.h"
+#include "alias.h"
+#include "parser.h"
+#include "main.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
+#define IBUFSIZ (BUFSIZ + 1)
+
+MKINIT
+struct strpush {
+ struct strpush *prev; /* preceding string on stack */
+ char *prevstring;
+ int prevnleft;
+ struct alias *ap; /* if push was associated with an alias */
+ char *string; /* remember the string since it may change */
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+MKINIT
+struct parsefile {
+ struct parsefile *prev; /* preceding file on stack */
+ int linno; /* current line */
+ int fd; /* file descriptor (or -1 if string) */
+ int nleft; /* number of chars left in this line */
+ int lleft; /* number of chars left in this buffer */
+ char *nextc; /* next char in buffer */
+ char *buf; /* input buffer */
+ struct strpush *strpush; /* for pushing strings at this level */
+ struct strpush basestrpush; /* so pushing one is fast */
+};
+
+
+int plinno = 1; /* input line number */
+int parsenleft; /* copy of parsefile->nleft */
+MKINIT int parselleft; /* copy of parsefile->lleft */
+char *parsenextc; /* copy of parsefile->nextc */
+MKINIT struct parsefile basepf; /* top level input file */
+MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */
+struct parsefile *parsefile = &basepf; /* current input file */
+int whichprompt; /* 1 == PS1, 2 == PS2 */
+
+#ifndef SMALL
+EditLine *el; /* cookie for editline package */
+#endif
+
+STATIC void pushfile(void);
+static int preadfd(void);
+static void setinputfd(int fd, int push);
+
+#ifdef mkinit
+INCLUDE <stdio.h>
+INCLUDE "input.h"
+INCLUDE "error.h"
+
+INIT {
+ basepf.nextc = basepf.buf = basebuf;
+}
+
+RESET {
+ parselleft = parsenleft = 0; /* clear input buffer */
+ popallfiles();
+}
+#endif
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc(void)
+{
+ return pgetc_macro();
+}
+
+
+/*
+ * Same as pgetc(), but ignores PEOA.
+ */
+
+int
+pgetc2()
+{
+ int c;
+ do {
+ c = pgetc_macro();
+ } while (c == PEOA);
+ return c;
+}
+
+
+static int
+preadfd(void)
+{
+ int nr;
+ char *buf = parsefile->buf;
+ parsenextc = buf;
+
+retry:
+#ifndef SMALL
+ if (parsefile->fd == 0 && el) {
+ static const char *rl_cp;
+ static int el_len;
+
+ if (rl_cp == NULL)
+ rl_cp = el_gets(el, &el_len);
+ if (rl_cp == NULL)
+ nr = 0;
+ else {
+ nr = el_len;
+ if (nr > IBUFSIZ - 1)
+ nr = IBUFSIZ - 1;
+ memcpy(buf, rl_cp, nr);
+ if (nr != el_len) {
+ el_len -= nr;
+ rl_cp += nr;
+ } else
+ rl_cp = 0;
+ }
+
+ } else
+#endif
+
+#ifdef HETIO
+ nr = hetio_read_input(parsefile->fd);
+ if (nr == -255)
+#endif
+ nr = read(parsefile->fd, buf, IBUFSIZ - 1);
+
+
+ if (nr < 0) {
+ if (errno == EINTR)
+ goto retry;
+ if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+ int flags = fcntl(0, F_GETFL, 0);
+ if (flags >= 0 && flags & O_NONBLOCK) {
+ flags &=~ O_NONBLOCK;
+ if (fcntl(0, F_SETFL, flags) >= 0) {
+ out2str("sh: turning off NDELAY mode\n");
+ goto retry;
+ }
+ }
+ }
+ }
+ return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ * from a string so we can't refill the buffer, return EOF.
+ * 3) If the is more stuff in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+ char *q;
+ int more;
+#ifndef SMALL
+ int something;
+#endif
+ char savec;
+
+ while (unlikely(parsefile->strpush)) {
+ if (
+ parsenleft == -1 && parsefile->strpush->ap &&
+ parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
+ ) {
+ return PEOA;
+ }
+ popstring();
+ if (--parsenleft >= 0)
+ return (signed char)*parsenextc++;
+ }
+ if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
+ return PEOF;
+ flushout(&output);
+#ifdef FLUSHERR
+ flushout(&errout);
+#endif
+
+ more = parselleft;
+ if (more <= 0) {
+again:
+ if ((more = preadfd()) <= 0) {
+ parselleft = parsenleft = EOF_NLEFT;
+ return PEOF;
+ }
+ }
+
+ q = parsenextc;
+
+ /* delete nul characters */
+#ifndef SMALL
+ something = 0;
+#endif
+ for (;;) {
+ int c;
+
+ more--;
+ c = *q;
+
+ if (!c)
+ memmove(q, q + 1, more);
+ else {
+ q++;
+
+ if (c == '\n') {
+ parsenleft = q - parsenextc - 1;
+ break;
+ }
+
+#ifndef SMALL
+ switch (c) {
+ default:
+ something = 1;
+ /* fall through */
+ case '\t':
+ case ' ':
+ break;
+ }
+#endif
+ }
+
+ if (more <= 0) {
+ parsenleft = q - parsenextc - 1;
+ if (parsenleft < 0)
+ goto again;
+ break;
+ }
+ }
+ parselleft = more;
+
+ savec = *q;
+ *q = '\0';
+
+#ifndef SMALL
+ if (parsefile->fd == 0 && hist && something) {
+ HistEvent he;
+ INTOFF;
+ history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
+ parsenextc);
+ INTON;
+ }
+#endif
+
+ if (vflag) {
+ out2str(parsenextc);
+#ifdef FLUSHERR
+ flushout(out2);
+#endif
+ }
+
+ *q = savec;
+
+ return (signed char)*parsenextc++;
+}
+
+/*
+ * Undo the last call to pgetc. Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+ parsenleft++;
+ parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(char *s, void *ap)
+{
+ struct strpush *sp;
+ size_t len;
+
+ len = strlen(s);
+ INTOFF;
+/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
+ if (parsefile->strpush) {
+ sp = ckmalloc(sizeof (struct strpush));
+ sp->prev = parsefile->strpush;
+ parsefile->strpush = sp;
+ } else
+ sp = parsefile->strpush = &(parsefile->basestrpush);
+ sp->prevstring = parsenextc;
+ sp->prevnleft = parsenleft;
+ sp->ap = (struct alias *)ap;
+ if (ap) {
+ ((struct alias *)ap)->flag |= ALIASINUSE;
+ sp->string = s;
+ }
+ parsenextc = s;
+ parsenleft = len;
+ INTON;
+}
+
+void
+popstring(void)
+{
+ struct strpush *sp = parsefile->strpush;
+
+ INTOFF;
+ if (sp->ap) {
+ if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+ checkkwd |= CHKALIAS;
+ }
+ if (sp->string != sp->ap->val) {
+ ckfree(sp->string);
+ }
+ sp->ap->flag &= ~ALIASINUSE;
+ if (sp->ap->flag & ALIASDEAD) {
+ unalias(sp->ap->name);
+ }
+ }
+ parsenextc = sp->prevstring;
+ parsenleft = sp->prevnleft;
+/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+ parsefile->strpush = sp->prev;
+ if (sp != &(parsefile->basestrpush))
+ ckfree(sp);
+ INTON;
+}
+
+/*
+ * Set the input to take input from a file. If push is set, push the
+ * old input onto the stack first.
+ */
+
+int
+setinputfile(const char *fname, int flags)
+{
+ int fd;
+
+ INTOFF;
+ if ((fd = open(fname, O_RDONLY)) < 0) {
+ if (flags & INPUT_NOFILE_OK)
+ goto out;
+ exitstatus = 127;
+ exerror(EXERROR, "Can't open %s", fname);
+ }
+ if (fd < 10)
+ fd = savefd(fd, fd);
+ setinputfd(fd, flags & INPUT_PUSH_FILE);
+out:
+ INTON;
+ return fd;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor. Call this with
+ * interrupts off.
+ */
+
+static void
+setinputfd(int fd, int push)
+{
+ if (push) {
+ pushfile();
+ parsefile->buf = 0;
+ }
+ parsefile->fd = fd;
+ if (parsefile->buf == NULL)
+ parsefile->buf = ckmalloc(IBUFSIZ);
+ parselleft = parsenleft = 0;
+ plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(char *string)
+{
+ INTOFF;
+ pushfile();
+ parsenextc = string;
+ parsenleft = strlen(string);
+ parsefile->buf = NULL;
+ plinno = 1;
+ INTON;
+}
+
+
+
+/*
+ * To handle the "." command, a stack of input files is used. Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+STATIC void
+pushfile(void)
+{
+ struct parsefile *pf;
+
+ parsefile->nleft = parsenleft;
+ parsefile->lleft = parselleft;
+ parsefile->nextc = parsenextc;
+ parsefile->linno = plinno;
+ pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+ pf->prev = parsefile;
+ pf->fd = -1;
+ pf->strpush = NULL;
+ pf->basestrpush.prev = NULL;
+ parsefile = pf;
+}
+
+
+void
+popfile(void)
+{
+ struct parsefile *pf = parsefile;
+
+ INTOFF;
+ if (pf->fd >= 0)
+ close(pf->fd);
+ if (pf->buf)
+ ckfree(pf->buf);
+ while (pf->strpush)
+ popstring();
+ parsefile = pf->prev;
+ ckfree(pf);
+ parsenleft = parsefile->nleft;
+ parselleft = parsefile->lleft;
+ parsenextc = parsefile->nextc;
+ plinno = parsefile->linno;
+ INTON;
+}
+
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles(void)
+{
+ while (parsefile != &basepf)
+ popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from. Called
+ * after a fork is done.
+ */
+
+void
+closescript(void)
+{
+ popallfiles();
+ if (parsefile->fd > 0) {
+ close(parsefile->fd);
+ parsefile->fd = 0;
+ }
+}
diff --git a/usr/dash/input.h b/usr/dash/input.h
new file mode 100644
index 0000000..50a7797
--- /dev/null
+++ b/usr/dash/input.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)input.h 8.2 (Berkeley) 5/4/95
+ */
+
+/* PEOF (the end of file marker) is defined in syntax.h */
+
+enum {
+ INPUT_PUSH_FILE = 1,
+ INPUT_NOFILE_OK = 2,
+};
+
+/*
+ * The input line number. Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped. The user of this
+ * package must set its value.
+ */
+extern int plinno;
+extern int parsenleft; /* number of characters left in input buffer */
+extern char *parsenextc; /* next character in input buffer */
+
+int pgetc(void);
+int pgetc2(void);
+int preadbuffer(void);
+void pungetc(void);
+void pushstring(char *, void *);
+void popstring(void);
+int setinputfile(const char *, int);
+void setinputstring(char *);
+void popfile(void);
+void popallfiles(void);
+void closescript(void);
+
+#define pgetc_macro() \
+ (--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff --git a/usr/dash/jobs.c b/usr/dash/jobs.c
new file mode 100644
index 0000000..f027cc1
--- /dev/null
+++ b/usr/dash/jobs.c
@@ -0,0 +1,1504 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef BSD
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <sys/ioctl.h>
+
+#include "shell.h"
+#if JOBS
+#include <termios.h>
+#undef CEOF /* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "system.h"
+
+/* mode flags for set_curjob */
+#define CUR_DELETE 2
+#define CUR_RUNNING 1
+#define CUR_STOPPED 0
+
+/* mode flags for dowait */
+#define DOWAIT_NORMAL 0
+#define DOWAIT_BLOCK 1
+#define DOWAIT_WAITCMD 2
+
+/* array of jobs */
+static struct job *jobtab;
+/* size of array */
+static unsigned njobs;
+/* pid of last background process */
+pid_t backgndpid;
+
+#if JOBS
+/* pgrp of shell on invocation */
+static int initialpgrp;
+/* control terminal */
+static int ttyfd = -1;
+#endif
+
+/* current job */
+static struct job *curjob;
+/* number of presumed living untracked jobs */
+static int jobless;
+
+STATIC void set_curjob(struct job *, unsigned);
+STATIC int jobno(const struct job *);
+STATIC int sprint_status(char *, int, int);
+STATIC void freejob(struct job *);
+STATIC struct job *getjob(const char *, int);
+STATIC struct job *growjobtab(void);
+STATIC void forkchild(struct job *, union node *, int);
+STATIC void forkparent(struct job *, union node *, int, pid_t);
+STATIC int dowait(int, struct job *);
+#ifdef SYSV
+STATIC int onsigchild(void);
+#endif
+STATIC int waitproc(int, int *);
+STATIC char *commandtext(union node *);
+STATIC void cmdtxt(union node *);
+STATIC void cmdlist(union node *, int);
+STATIC void cmdputs(const char *);
+STATIC void showpipe(struct job *, struct output *);
+STATIC int getstatus(struct job *);
+
+#if JOBS
+static int restartjob(struct job *, int);
+static void xtcsetpgrp(int, pid_t);
+#endif
+
+STATIC void
+set_curjob(struct job *jp, unsigned mode)
+{
+ struct job *jp1;
+ struct job **jpp, **curp;
+
+ /* first remove from list */
+ jpp = curp = &curjob;
+ do {
+ jp1 = *jpp;
+ if (jp1 == jp)
+ break;
+ jpp = &jp1->prev_job;
+ } while (1);
+ *jpp = jp1->prev_job;
+
+ /* Then re-insert in correct position */
+ jpp = curp;
+ switch (mode) {
+ default:
+#ifdef DEBUG
+ abort();
+#endif
+ case CUR_DELETE:
+ /* job being deleted */
+ break;
+ case CUR_RUNNING:
+ /* newly created job or backgrounded job,
+ put after all stopped jobs. */
+ do {
+ jp1 = *jpp;
+ if (!JOBS || !jp1 || jp1->state != JOBSTOPPED)
+ break;
+ jpp = &jp1->prev_job;
+ } while (1);
+ /* FALLTHROUGH */
+#if JOBS
+ case CUR_STOPPED:
+#endif
+ /* newly stopped job - becomes curjob */
+ jp->prev_job = *jpp;
+ *jpp = jp;
+ break;
+ }
+}
+
+#if JOBS
+/*
+ * Turn job control on and off.
+ *
+ * Note: This code assumes that the third arg to ioctl is a character
+ * pointer, which is true on Berkeley systems but not System V. Since
+ * System V doesn't have job control yet, this isn't a problem now.
+ *
+ * Called with interrupts off.
+ */
+
+int jobctl;
+
+void
+setjobctl(int on)
+{
+ int fd;
+ int pgrp;
+
+ if (on == jobctl || rootshell == 0)
+ return;
+ if (on) {
+ int ofd;
+ ofd = fd = open(_PATH_TTY, O_RDWR);
+ if (fd < 0) {
+ fd += 3;
+ while (!isatty(fd))
+ if (--fd < 0)
+ goto out;
+ }
+ fd = savefd(fd, ofd);
+ do { /* while we are in the background */
+ if ((pgrp = tcgetpgrp(fd)) < 0) {
+out:
+ sh_warnx("can't access tty; job control turned off");
+ mflag = on = 0;
+ goto close;
+ }
+ if (pgrp == getpgrp())
+ break;
+ killpg(0, SIGTTIN);
+ } while (1);
+ initialpgrp = pgrp;
+
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ pgrp = rootpid;
+ setpgid(0, pgrp);
+ xtcsetpgrp(fd, pgrp);
+ } else {
+ /* turning job control off */
+ fd = ttyfd;
+ pgrp = initialpgrp;
+ xtcsetpgrp(fd, pgrp);
+ setpgid(0, pgrp);
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+close:
+ close(fd);
+ fd = -1;
+ }
+ ttyfd = fd;
+ jobctl = on;
+}
+#endif
+
+
+int
+killcmd(argc, argv)
+ int argc;
+ char **argv;
+{
+ int signo = -1;
+ int list = 0;
+ int i;
+ pid_t pid;
+ struct job *jp;
+
+ if (argc <= 1) {
+usage:
+ sh_error(
+"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
+"kill -l [exitstatus]"
+ );
+ }
+
+ if (**++argv == '-') {
+ signo = decode_signal(*argv + 1, 1);
+ if (signo < 0) {
+ int c;
+
+ while ((c = nextopt("ls:")) != '\0')
+ switch (c) {
+ default:
+#ifdef DEBUG
+ abort();
+#endif
+ case 'l':
+ list = 1;
+ break;
+ case 's':
+ signo = decode_signal(optionarg, 1);
+ if (signo < 0) {
+ sh_error(
+ "invalid signal number or name: %s",
+ optionarg
+ );
+ }
+ break;
+ }
+ argv = argptr;
+ } else
+ argv++;
+ }
+
+ if (!list && signo < 0)
+ signo = SIGTERM;
+
+ if ((signo < 0 || !*argv) ^ list) {
+ goto usage;
+ }
+
+ if (list) {
+ struct output *out;
+
+ out = out1;
+ if (!*argv) {
+ outstr("0\n", out);
+ for (i = 1; i < NSIG; i++) {
+ outfmt(out, snlfmt, signal_name(i));
+ }
+ return 0;
+ }
+ signo = number(*argv);
+ if (signo > 128)
+ signo -= 128;
+ if (0 < signo && signo < NSIG)
+ outfmt(out, snlfmt, signal_name(signo));
+ else
+ sh_error("invalid signal number or exit status: %s",
+ *argv);
+ return 0;
+ }
+
+ i = 0;
+ do {
+ if (**argv == '%') {
+ jp = getjob(*argv, 0);
+ pid = -jp->ps[0].pid;
+ } else
+ pid = **argv == '-' ?
+ -number(*argv + 1) : number(*argv);
+ if (kill(pid, signo) != 0) {
+ sh_warnx("%s\n", strerror(errno));
+ i = 1;
+ }
+ } while (*++argv);
+
+ return i;
+}
+
+STATIC int
+jobno(const struct job *jp)
+{
+ return jp - jobtab + 1;
+}
+
+#if JOBS
+int
+fgcmd(int argc, char **argv)
+{
+ struct job *jp;
+ struct output *out;
+ int mode;
+ int retval;
+
+ mode = (**argv == 'f') ? FORK_FG : FORK_BG;
+ nextopt(nullstr);
+ argv = argptr;
+ out = out1;
+ do {
+ jp = getjob(*argv, 1);
+ if (mode == FORK_BG) {
+ set_curjob(jp, CUR_RUNNING);
+ outfmt(out, "[%d] ", jobno(jp));
+ }
+ outstr(jp->ps->cmd, out);
+ showpipe(jp, out);
+ retval = restartjob(jp, mode);
+ } while (*argv && *++argv);
+ return retval;
+}
+
+int bgcmd(int argc, char **argv)
+#ifdef HAVE_ALIAS_ATTRIBUTE
+ __attribute__((__alias__("fgcmd")));
+#else
+{
+ return fgcmd(argc, argv);
+}
+#endif
+
+
+STATIC int
+restartjob(struct job *jp, int mode)
+{
+ struct procstat *ps;
+ int i;
+ int status;
+ pid_t pgid;
+
+ INTOFF;
+ if (jp->state == JOBDONE)
+ goto out;
+ jp->state = JOBRUNNING;
+ pgid = jp->ps->pid;
+ if (mode == FORK_FG)
+ xtcsetpgrp(ttyfd, pgid);
+ killpg(pgid, SIGCONT);
+ ps = jp->ps;
+ i = jp->nprocs;
+ do {
+ if (WIFSTOPPED(ps->status)) {
+ ps->status = -1;
+ }
+ } while (ps++, --i);
+out:
+ status = (mode == FORK_FG) ? waitforjob(jp) : 0;
+ INTON;
+ return status;
+}
+#endif
+
+STATIC int
+sprint_status(char *s, int status, int sigonly)
+{
+ int col;
+ int st;
+
+ col = 0;
+ st = WEXITSTATUS(status);
+ if (!WIFEXITED(status)) {
+#if JOBS
+ st = WSTOPSIG(status);
+ if (!WIFSTOPPED(status))
+#endif
+ st = WTERMSIG(status);
+ if (sigonly) {
+ if (st == SIGINT || st == SIGPIPE)
+ goto out;
+#if JOBS
+ if (WIFSTOPPED(status))
+ goto out;
+#endif
+ }
+ col = fmtstr(s, 32, "%s", strsignal(st));
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ col += fmtstr(s + col, 16, " (core dumped)");
+ }
+#endif
+ } else if (!sigonly) {
+ if (st)
+ col = fmtstr(s, 16, "Done(%d)", st);
+ else
+ col = fmtstr(s, 16, "Done");
+ }
+
+out:
+ return col;
+}
+
+static void
+showjob(struct output *out, struct job *jp, int mode)
+{
+ struct procstat *ps;
+ struct procstat *psend;
+ int col;
+ int indent;
+ char s[80];
+
+ ps = jp->ps;
+
+ if (mode & SHOW_PGID) {
+ /* just output process (group) id of pipeline */
+ outfmt(out, "%d\n", ps->pid);
+ return;
+ }
+
+ col = fmtstr(s, 16, "[%d] ", jobno(jp));
+ indent = col;
+
+ if (jp == curjob)
+ s[col - 2] = '+';
+ else if (curjob && jp == curjob->prev_job)
+ s[col - 2] = '-';
+
+ if (mode & SHOW_PID)
+ col += fmtstr(s + col, 16, "%d ", ps->pid);
+
+ psend = ps + jp->nprocs;
+
+ if (jp->state == JOBRUNNING) {
+ scopy("Running", s + col);
+ col += strlen("Running");
+ } else {
+ int status = psend[-1].status;
+#if JOBS
+ if (jp->state == JOBSTOPPED)
+ status = jp->stopstatus;
+#endif
+ col += sprint_status(s + col, status, 0);
+ }
+
+ goto start;
+
+ do {
+ /* for each process */
+ col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
+
+start:
+ outfmt(
+ out, "%s%*c%s",
+ s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
+ );
+ if (!(mode & SHOW_PID)) {
+ showpipe(jp, out);
+ break;
+ }
+ if (++ps == psend) {
+ outcslow('\n', out);
+ break;
+ }
+ } while (1);
+
+ jp->changed = 0;
+
+ if (jp->state == JOBDONE) {
+ TRACE(("showjob: freeing job %d\n", jobno(jp)));
+ freejob(jp);
+ }
+}
+
+
+int
+jobscmd(int argc, char **argv)
+{
+ int mode, m;
+ struct output *out;
+
+ mode = 0;
+ while ((m = nextopt("lp")))
+ if (m == 'l')
+ mode = SHOW_PID;
+ else
+ mode = SHOW_PGID;
+
+ out = out1;
+ argv = argptr;
+ if (*argv)
+ do
+ showjob(out, getjob(*argv,0), mode);
+ while (*++argv);
+ else
+ showjobs(out, mode);
+
+ return 0;
+}
+
+
+/*
+ * Print a list of jobs. If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ */
+
+void
+showjobs(struct output *out, int mode)
+{
+ struct job *jp;
+
+ TRACE(("showjobs(%x) called\n", mode));
+
+ /* If not even one one job changed, there is nothing to do */
+ while (dowait(DOWAIT_NORMAL, NULL) > 0)
+ continue;
+
+ for (jp = curjob; jp; jp = jp->prev_job) {
+ if (!(mode & SHOW_CHANGED) || jp->changed)
+ showjob(out, jp, mode);
+ }
+}
+
+/*
+ * Mark a job structure as unused.
+ */
+
+STATIC void
+freejob(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ INTOFF;
+ for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+ if (ps->cmd != nullstr)
+ ckfree(ps->cmd);
+ }
+ if (jp->ps != &jp->ps0)
+ ckfree(jp->ps);
+ jp->used = 0;
+ set_curjob(jp, CUR_DELETE);
+ INTON;
+}
+
+
+
+int
+waitcmd(int argc, char **argv)
+{
+ struct job *job;
+ int retval;
+ struct job *jp;
+
+ nextopt(nullstr);
+ retval = 0;
+
+ argv = argptr;
+ if (!*argv) {
+ /* wait for all jobs */
+ for (;;) {
+ jp = curjob;
+ while (1) {
+ if (!jp) {
+ /* no running procs */
+ goto out;
+ }
+ if (jp->state == JOBRUNNING)
+ break;
+ jp->waited = 1;
+ jp = jp->prev_job;
+ }
+ if (dowait(DOWAIT_WAITCMD, 0) <= 0)
+ goto sigout;
+ }
+ }
+
+ retval = 127;
+ do {
+ if (**argv != '%') {
+ pid_t pid = number(*argv);
+ job = curjob;
+ goto start;
+ do {
+ if (job->ps[job->nprocs - 1].pid == pid)
+ break;
+ job = job->prev_job;
+start:
+ if (!job)
+ goto repeat;
+ } while (1);
+ } else
+ job = getjob(*argv, 0);
+ /* loop until process terminated or stopped */
+ while (job->state == JOBRUNNING)
+ if (dowait(DOWAIT_WAITCMD, 0) <= 0)
+ goto sigout;
+ job->waited = 1;
+ retval = getstatus(job);
+repeat:
+ ;
+ } while (*++argv);
+
+out:
+ return retval;
+
+sigout:
+ retval = 128 + pendingsigs;
+ goto out;
+}
+
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+STATIC struct job *
+getjob(const char *name, int getctl)
+{
+ struct job *jp;
+ struct job *found;
+ const char *err_msg = "No such job: %s";
+ unsigned num;
+ int c;
+ const char *p;
+ char *(*match)(const char *, const char *);
+
+ jp = curjob;
+ p = name;
+ if (!p)
+ goto currentjob;
+
+ if (*p != '%')
+ goto err;
+
+ c = *++p;
+ if (!c)
+ goto currentjob;
+
+ if (!p[1]) {
+ if (c == '+' || c == '%') {
+currentjob:
+ err_msg = "No current job";
+ goto check;
+ } else if (c == '-') {
+ if (jp)
+ jp = jp->prev_job;
+ err_msg = "No previous job";
+check:
+ if (!jp)
+ goto err;
+ goto gotit;
+ }
+ }
+
+ if (is_number(p)) {
+ num = atoi(p);
+ if (num < njobs) {
+ jp = jobtab + num - 1;
+ if (jp->used)
+ goto gotit;
+ goto err;
+ }
+ }
+
+ match = prefix;
+ if (*p == '?') {
+ match = strstr;
+ p++;
+ }
+
+ found = 0;
+ while (1) {
+ if (!jp)
+ goto err;
+ if (match(jp->ps[0].cmd, p)) {
+ if (found)
+ goto err;
+ found = jp;
+ err_msg = "%s: ambiguous";
+ }
+ jp = jp->prev_job;
+ }
+
+gotit:
+#if JOBS
+ err_msg = "job %s not created under job control";
+ if (getctl && jp->jobctl == 0)
+ goto err;
+#endif
+ return jp;
+err:
+ sh_error(err_msg, name);
+}
+
+
+
+/*
+ * Return a new job structure.
+ * Called with interrupts off.
+ */
+
+struct job *
+makejob(union node *node, int nprocs)
+{
+ int i;
+ struct job *jp;
+
+ for (i = njobs, jp = jobtab ; ; jp++) {
+ if (--i < 0) {
+ jp = growjobtab();
+ break;
+ }
+ if (jp->used == 0)
+ break;
+ if (jp->state != JOBDONE || !jp->waited)
+ continue;
+ if (jobctl)
+ continue;
+ freejob(jp);
+ break;
+ }
+ memset(jp, 0, sizeof(*jp));
+#if JOBS
+ if (jobctl)
+ jp->jobctl = 1;
+#endif
+ jp->prev_job = curjob;
+ curjob = jp;
+ jp->used = 1;
+ jp->ps = &jp->ps0;
+ if (nprocs > 1) {
+ jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+ }
+ TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+ jobno(jp)));
+ return jp;
+}
+
+STATIC struct job *
+growjobtab(void)
+{
+ size_t len;
+ ptrdiff_t offset;
+ struct job *jp, *jq;
+
+ len = njobs * sizeof(*jp);
+ jq = jobtab;
+ jp = ckrealloc(jq, len + 4 * sizeof(*jp));
+
+ offset = (char *)jp - (char *)jq;
+ if (offset) {
+ /* Relocate pointers */
+ size_t l = len;
+
+ jq = (struct job *)((char *)jq + l);
+ while (l) {
+ l -= sizeof(*jp);
+ jq--;
+#define joff(p) ((struct job *)((char *)(p) + l))
+#define jmove(p) (p) = (void *)((char *)(p) + offset)
+ if (likely(joff(jp)->ps == &jq->ps0))
+ jmove(joff(jp)->ps);
+ if (joff(jp)->prev_job)
+ jmove(joff(jp)->prev_job);
+ }
+ if (curjob)
+ jmove(curjob);
+#undef joff
+#undef jmove
+ }
+
+ njobs += 4;
+ jobtab = jp;
+ jp = (struct job *)((char *)jp + len);
+ jq = jp + 3;
+ do {
+ jq->used = 0;
+ } while (--jq >= jp);
+ return jp;
+}
+
+
+/*
+ * Fork off a subshell. If we are doing job control, give the subshell its
+ * own process group. Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child. Both jp and n may
+ * be NULL. The mode parameter can be one of the following:
+ * FORK_FG - Fork off a foreground process.
+ * FORK_BG - Fork off a background process.
+ * FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ * process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ *
+ * Called with interrupts off.
+ */
+
+STATIC inline void
+forkchild(struct job *jp, union node *n, int mode)
+{
+ int oldlvl;
+
+ TRACE(("Child shell %d\n", getpid()));
+ oldlvl = shlvl;
+ shlvl++;
+
+ closescript();
+ clear_traps();
+#if JOBS
+ /* do job control only in root shell */
+ jobctl = 0;
+ if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
+ pid_t pgrp;
+
+ if (jp->nprocs == 0)
+ pgrp = getpid();
+ else
+ pgrp = jp->ps[0].pid;
+ /* This can fail because we are doing it in the parent also */
+ (void)setpgid(0, pgrp);
+ if (mode == FORK_FG)
+ xtcsetpgrp(ttyfd, pgrp);
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ } else
+#endif
+ if (mode == FORK_BG) {
+ ignoresig(SIGINT);
+ ignoresig(SIGQUIT);
+ if (jp->nprocs == 0) {
+ close(0);
+ if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+ sh_error("Can't open %s", _PATH_DEVNULL);
+ }
+ }
+ if (!oldlvl && iflag) {
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+ }
+ for (jp = curjob; jp; jp = jp->prev_job)
+ freejob(jp);
+ jobless = 0;
+}
+
+STATIC inline void
+forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+{
+ TRACE(("In parent shell: child = %d\n", pid));
+ if (!jp) {
+ while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
+ jobless++;
+ return;
+ }
+#if JOBS
+ if (mode != FORK_NOJOB && jp->jobctl) {
+ int pgrp;
+
+ if (jp->nprocs == 0)
+ pgrp = pid;
+ else
+ pgrp = jp->ps[0].pid;
+ /* This can fail because we are doing it in the child also */
+ (void)setpgid(pid, pgrp);
+ }
+#endif
+ if (mode == FORK_BG) {
+ backgndpid = pid; /* set $! */
+ set_curjob(jp, CUR_RUNNING);
+ }
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ if (jobctl && n)
+ ps->cmd = commandtext(n);
+ }
+}
+
+int
+forkshell(struct job *jp, union node *n, int mode)
+{
+ int pid;
+
+ TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
+ pid = fork();
+ if (pid < 0) {
+ TRACE(("Fork failed, errno=%d", errno));
+ if (jp)
+ freejob(jp);
+ sh_error("Cannot fork");
+ }
+ if (pid == 0)
+ forkchild(jp, n, mode);
+ else
+ forkparent(jp, n, mode, pid);
+ return pid;
+}
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell. This means that an infinite loop started by an inter-
+ * active user may be hard to kill. With job control turned off, an
+ * interactive user may place an interactive program inside a loop. If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop. The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * forground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ *
+ * Called with interrupts off.
+ */
+
+int
+waitforjob(struct job *jp)
+{
+ int st;
+
+ TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
+ while (jp->state == JOBRUNNING) {
+ dowait(DOWAIT_BLOCK, jp);
+ }
+ st = getstatus(jp);
+#if JOBS
+ if (jp->jobctl) {
+ xtcsetpgrp(ttyfd, rootpid);
+ /*
+ * This is truly gross.
+ * If we're doing job control, then we did a TIOCSPGRP which
+ * caused us (the shell) to no longer be in the controlling
+ * session -- so we wouldn't have seen any ^C/SIGINT. So, we
+ * intuit from the subprocess exit status whether a SIGINT
+ * occurred, and if so interrupt ourselves. Yuck. - mycroft
+ */
+ if (jp->sigint)
+ raise(SIGINT);
+ }
+#endif
+ if (! JOBS || jp->state == JOBDONE)
+ freejob(jp);
+ return st;
+}
+
+
+
+/*
+ * Wait for a process to terminate.
+ */
+
+STATIC int
+dowait(int block, struct job *job)
+{
+ int pid;
+ int status;
+ struct job *jp;
+ struct job *thisjob = NULL;
+ int state;
+
+ INTOFF;
+ TRACE(("dowait(%d) called\n", block));
+ pid = waitproc(block, &status);
+ TRACE(("wait returns pid %d, status=%d\n", pid, status));
+ if (pid <= 0)
+ goto out;
+
+ for (jp = curjob; jp; jp = jp->prev_job) {
+ struct procstat *sp;
+ struct procstat *spend;
+ if (jp->state == JOBDONE)
+ continue;
+ state = JOBDONE;
+ spend = jp->ps + jp->nprocs;
+ sp = jp->ps;
+ do {
+ if (sp->pid == pid) {
+ TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
+ sp->status = status;
+ thisjob = jp;
+ }
+ if (sp->status == -1)
+ state = JOBRUNNING;
+#if JOBS
+ if (state == JOBRUNNING)
+ continue;
+ if (WIFSTOPPED(sp->status)) {
+ jp->stopstatus = sp->status;
+ state = JOBSTOPPED;
+ }
+#endif
+ } while (++sp < spend);
+ if (thisjob)
+ goto gotjob;
+ }
+ if (!JOBS || !WIFSTOPPED(status))
+ jobless--;
+ goto out;
+
+gotjob:
+ if (state != JOBRUNNING) {
+ thisjob->changed = 1;
+
+ if (thisjob->state != state) {
+ TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
+ thisjob->state = state;
+#if JOBS
+ if (state == JOBSTOPPED) {
+ set_curjob(thisjob, CUR_STOPPED);
+ }
+#endif
+ }
+ }
+
+out:
+ INTON;
+
+ if (thisjob && thisjob == job) {
+ char s[48 + 1];
+ int len;
+
+ len = sprint_status(s, status, 1);
+ if (len) {
+ s[len] = '\n';
+ s[len + 1] = 0;
+ outstr(s, out2);
+ }
+ }
+ return pid;
+}
+
+
+
+/*
+ * Do a wait system call. If job control is compiled in, we accept
+ * stopped processes. If block is zero, we return a value of zero
+ * rather than blocking.
+ *
+ * System V doesn't have a non-blocking wait system call. It does
+ * have a SIGCLD signal that is sent to a process when one of it's
+ * children dies. The obvious way to use SIGCLD would be to install
+ * a handler for SIGCLD which simply bumped a counter when a SIGCLD
+ * was received, and have waitproc bump another counter when it got
+ * the status of a process. Waitproc would then know that a wait
+ * system call would not block if the two counters were different.
+ * This approach doesn't work because if a process has children that
+ * have not been waited for, System V will send it a SIGCLD when it
+ * installs a signal handler for SIGCLD. What this means is that when
+ * a child exits, the shell will be sent SIGCLD signals continuously
+ * until is runs out of stack space, unless it does a wait call before
+ * restoring the signal handler. The code below takes advantage of
+ * this (mis)feature by installing a signal handler for SIGCLD and
+ * then checking to see whether it was called. If there are any
+ * children to be waited for, it will be.
+ *
+ * If neither SYSV nor BSD is defined, we don't implement nonblocking
+ * waits at all. In this case, the user will not be informed when
+ * a background process until the next time she runs a real program
+ * (as opposed to running a builtin command or just typing return),
+ * and the jobs command may give out of date information.
+ */
+
+#ifdef SYSV
+STATIC int gotsigchild;
+
+STATIC int onsigchild() {
+ gotsigchild = 1;
+}
+#endif
+
+
+STATIC int
+waitproc(int block, int *status)
+{
+ sigset_t mask, oldmask;
+ int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
+ int err;
+
+#if JOBS
+ if (jobctl)
+ flags |= WUNTRACED;
+#endif
+
+ do {
+ gotsigchld = 0;
+ err = wait3(status, flags, NULL);
+ if (err || !block)
+ break;
+
+ block = 0;
+
+ sigfillset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, &oldmask);
+
+ while (!gotsigchld && !pendingsigs)
+ sigsuspend(&oldmask);
+
+ sigclearmask();
+ } while (gotsigchld);
+
+ return err;
+}
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning;
+int
+stoppedjobs(void)
+{
+ struct job *jp;
+ int retval;
+
+ retval = 0;
+ if (job_warning)
+ goto out;
+ jp = curjob;
+ if (jp && jp->state == JOBSTOPPED) {
+ out2str("You have stopped jobs.\n");
+ job_warning = 2;
+ retval++;
+ }
+
+out:
+ return retval;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command).
+ */
+
+STATIC char *cmdnextc;
+
+STATIC char *
+commandtext(union node *n)
+{
+ char *name;
+
+ STARTSTACKSTR(cmdnextc);
+ cmdtxt(n);
+ name = stackblock();
+ TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
+ return savestr(name);
+}
+
+
+STATIC void
+cmdtxt(union node *n)
+{
+ union node *np;
+ struct nodelist *lp;
+ const char *p;
+ char s[2];
+
+ if (!n)
+ return;
+ switch (n->type) {
+ default:
+#if DEBUG
+ abort();
+#endif
+ case NPIPE:
+ lp = n->npipe.cmdlist;
+ for (;;) {
+ cmdtxt(lp->n);
+ lp = lp->next;
+ if (!lp)
+ break;
+ cmdputs(" | ");
+ }
+ break;
+ case NSEMI:
+ p = "; ";
+ goto binop;
+ case NAND:
+ p = " && ";
+ goto binop;
+ case NOR:
+ p = " || ";
+binop:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs(p);
+ n = n->nbinary.ch2;
+ goto donode;
+ case NREDIR:
+ case NBACKGND:
+ n = n->nredir.n;
+ goto donode;
+ case NNOT:
+ cmdputs("!");
+ n = n->nnot.com;
+donode:
+ cmdtxt(n);
+ break;
+ case NIF:
+ cmdputs("if ");
+ cmdtxt(n->nif.test);
+ cmdputs("; then ");
+ if (n->nif.elsepart) {
+ cmdtxt(n->nif.ifpart);
+ cmdputs("; else ");
+ n = n->nif.elsepart;
+ } else {
+ n = n->nif.ifpart;
+ }
+ p = "; fi";
+ goto dotail;
+ case NSUBSHELL:
+ cmdputs("(");
+ n = n->nredir.n;
+ p = ")";
+ goto dotail;
+ case NWHILE:
+ p = "while ";
+ goto until;
+ case NUNTIL:
+ p = "until ";
+until:
+ cmdputs(p);
+ cmdtxt(n->nbinary.ch1);
+ n = n->nbinary.ch2;
+ p = "; done";
+dodo:
+ cmdputs("; do ");
+dotail:
+ cmdtxt(n);
+ goto dotail2;
+ case NFOR:
+ cmdputs("for ");
+ cmdputs(n->nfor.var);
+ cmdputs(" in ");
+ cmdlist(n->nfor.args, 1);
+ n = n->nfor.body;
+ p = "; done";
+ goto dodo;
+ case NDEFUN:
+ cmdputs(n->ndefun.text);
+ p = "() { ... }";
+ goto dotail2;
+ case NCMD:
+ cmdlist(n->ncmd.args, 1);
+ cmdlist(n->ncmd.redirect, 0);
+ break;
+ case NARG:
+ p = n->narg.text;
+dotail2:
+ cmdputs(p);
+ break;
+ case NHERE:
+ case NXHERE:
+ p = "<<...";
+ goto dotail2;
+ case NCASE:
+ cmdputs("case ");
+ cmdputs(n->ncase.expr->narg.text);
+ cmdputs(" in ");
+ for (np = n->ncase.cases; np; np = np->nclist.next) {
+ cmdtxt(np->nclist.pattern);
+ cmdputs(") ");
+ cmdtxt(np->nclist.body);
+ cmdputs(";; ");
+ }
+ p = "esac";
+ goto dotail2;
+ case NTO:
+ p = ">";
+ goto redir;
+ case NCLOBBER:
+ p = ">|";
+ goto redir;
+ case NAPPEND:
+ p = ">>";
+ goto redir;
+ case NTOFD:
+ p = ">&";
+ goto redir;
+ case NFROM:
+ p = "<";
+ goto redir;
+ case NFROMFD:
+ p = "<&";
+ goto redir;
+ case NFROMTO:
+ p = "<>";
+redir:
+ s[0] = n->nfile.fd + '0';
+ s[1] = '\0';
+ cmdputs(s);
+ cmdputs(p);
+ if (n->type == NTOFD || n->type == NFROMFD) {
+ s[0] = n->ndup.dupfd + '0';
+ p = s;
+ goto dotail2;
+ } else {
+ n = n->nfile.fname;
+ goto donode;
+ }
+ }
+}
+
+STATIC void
+cmdlist(union node *np, int sep)
+{
+ for (; np; np = np->narg.next) {
+ if (!sep)
+ cmdputs(spcstr);
+ cmdtxt(np);
+ if (sep && np->narg.next)
+ cmdputs(spcstr);
+ }
+}
+
+
+STATIC void
+cmdputs(const char *s)
+{
+ const char *p, *str;
+ char cc[2] = " ";
+ char *nextc;
+ signed char c;
+ int subtype = 0;
+ int quoted = 0;
+ static const char vstype[VSTYPE + 1][4] = {
+ "", "}", "-", "+", "?", "=",
+ "%", "%%", "#", "##",
+ };
+
+ nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
+ p = s;
+ while ((c = *p++) != 0) {
+ str = 0;
+ switch (c) {
+ case CTLESC:
+ c = *p++;
+ break;
+ case CTLVAR:
+ subtype = *p++;
+ if ((subtype & VSTYPE) == VSLENGTH)
+ str = "${#";
+ else
+ str = "${";
+ goto dostr;
+ case CTLENDVAR:
+ str = "\"}";
+ str += !(quoted & 1);
+ quoted >>= 1;
+ subtype = 0;
+ goto dostr;
+ case CTLBACKQ:
+ str = "$(...)";
+ goto dostr;
+ case CTLARI:
+ str = "$((";
+ goto dostr;
+ case CTLENDARI:
+ str = "))";
+ goto dostr;
+ case CTLQUOTEMARK:
+ quoted ^= 1;
+ c = '"';
+ break;
+ case '=':
+ if (subtype == 0)
+ break;
+ if ((subtype & VSTYPE) != VSNORMAL)
+ quoted <<= 1;
+ str = vstype[subtype & VSTYPE];
+ if (subtype & VSNUL)
+ c = ':';
+ else
+ goto checkstr;
+ break;
+ case '\'':
+ case '\\':
+ case '"':
+ case '$':
+ /* These can only happen inside quotes */
+ cc[0] = c;
+ str = cc;
+ c = '\\';
+ break;
+ default:
+ break;
+ }
+ USTPUTC(c, nextc);
+checkstr:
+ if (!str)
+ continue;
+dostr:
+ while ((c = *str++)) {
+ USTPUTC(c, nextc);
+ }
+ }
+ if (quoted & 1) {
+ USTPUTC('"', nextc);
+ }
+ *nextc = 0;
+ cmdnextc = nextc;
+}
+
+
+STATIC void
+showpipe(struct job *jp, struct output *out)
+{
+ struct procstat *sp;
+ struct procstat *spend;
+
+ spend = jp->ps + jp->nprocs;
+ for (sp = jp->ps + 1; sp < spend; sp++)
+ outfmt(out, " | %s", sp->cmd);
+ outcslow('\n', out);
+ flushall();
+}
+
+
+#if JOBS
+STATIC void
+xtcsetpgrp(int fd, pid_t pgrp)
+{
+ if (tcsetpgrp(fd, pgrp))
+ sh_error("Cannot set tty process group (%s)", strerror(errno));
+}
+#endif
+
+
+STATIC int
+getstatus(struct job *job) {
+ int status;
+ int retval;
+
+ status = job->ps[job->nprocs - 1].status;
+ retval = WEXITSTATUS(status);
+ if (!WIFEXITED(status)) {
+#if JOBS
+ retval = WSTOPSIG(status);
+ if (!WIFSTOPPED(status))
+#endif
+ {
+ /* XXX: limits number of signals */
+ retval = WTERMSIG(status);
+#if JOBS
+ if (retval == SIGINT)
+ job->sigint = 1;
+#endif
+ }
+ retval += 128;
+ }
+ TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
+ jobno(job), job->nprocs, status, retval));
+ return retval;
+}
diff --git a/usr/dash/jobs.h b/usr/dash/jobs.h
new file mode 100644
index 0000000..953ee87
--- /dev/null
+++ b/usr/dash/jobs.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)jobs.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+/* mode flags for showjob(s) */
+#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
+#define SHOW_PID 0x04 /* include process pid */
+#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
+
+
+/*
+ * A job structure contains information about a job. A job is either a
+ * single process or a set of processes contained in a pipeline. In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+ pid_t pid; /* process id */
+ int status; /* last process status from wait() */
+ char *cmd; /* text of command being run */
+};
+
+struct job {
+ struct procstat ps0; /* status of process */
+ struct procstat *ps; /* status or processes when more than one */
+#if JOBS
+ int stopstatus; /* status of a stopped job */
+#endif
+ uint32_t
+ nprocs: 16, /* number of processes */
+ state: 8,
+#define JOBRUNNING 0 /* at least one proc running */
+#define JOBSTOPPED 1 /* all procs are stopped */
+#define JOBDONE 2 /* all procs are completed */
+#if JOBS
+ sigint: 1, /* job was killed by SIGINT */
+ jobctl: 1, /* job running under job control */
+#endif
+ waited: 1, /* true if this entry has been waited for */
+ used: 1, /* true if this entry is in used */
+ changed: 1; /* true if status has changed */
+ struct job *prev_job; /* previous job */
+};
+
+extern pid_t backgndpid; /* pid of last background process */
+extern int job_warning; /* user was warned about stopped jobs */
+#if JOBS
+extern int jobctl; /* true if doing job control */
+#else
+#define jobctl 0
+#endif
+
+void setjobctl(int);
+int killcmd(int, char **);
+int fgcmd(int, char **);
+int bgcmd(int, char **);
+int jobscmd(int, char **);
+struct output;
+void showjobs(struct output *, int);
+int waitcmd(int, char **);
+struct job *makejob(union node *, int);
+int forkshell(struct job *, union node *, int);
+int waitforjob(struct job *);
+int stoppedjobs(void);
+
+#if ! JOBS
+#define setjobctl(on) ((void)(on)) /* do nothing */
+#endif
diff --git a/usr/dash/machdep.h b/usr/dash/machdep.h
new file mode 100644
index 0000000..b1ca07a
--- /dev/null
+++ b/usr/dash/machdep.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)machdep.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include "config.h"
+
+/*
+ * Most machines require the value returned from malloc to be aligned
+ * in some way. The following macro will get this right on many machines.
+ */
+#ifdef HAVE_STRTOD
+# define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
+#else
+# define SHELL_SIZE (sizeof(union {int i; char *cp;}) - 1)
+#endif
+
+/*
+ * It appears that grabstackstr() will barf with such alignments
+ * because stalloc() will return a string allocated in a new stackblock.
+ */
+#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
diff --git a/usr/dash/mail.c b/usr/dash/mail.c
new file mode 100644
index 0000000..02e07f7
--- /dev/null
+++ b/usr/dash/mail.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Routines to check for mail. (Perhaps make part of main.c?)
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "nodes.h"
+#include "exec.h" /* defines padvance() */
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mail.h"
+#include "mystring.h"
+
+
+#define MAXMBOXES 10
+
+/* times of mailboxes */
+static time_t mailtime[MAXMBOXES];
+/* Set if MAIL or MAILPATH is changed. */
+static int changed;
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived. If changed is set,
+ * then the value of MAIL has changed, so we just update the values.
+ */
+
+void
+chkmail(void)
+{
+ const char *mpath;
+ char *p;
+ char *q;
+ time_t *mtp;
+ struct stackmark smark;
+ struct stat64 statb;
+
+ setstackmark(&smark);
+ mpath = mpathset() ? mpathval() : mailval();
+ for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
+ p = padvance(&mpath, nullstr);
+ if (p == NULL)
+ break;
+ if (*p == '\0')
+ continue;
+ for (q = p ; *q ; q++);
+#ifdef DEBUG
+ if (q[-1] != '/')
+ abort();
+#endif
+ q[-1] = '\0'; /* delete trailing '/' */
+ if (stat64(p, &statb) < 0) {
+ *mtp = 0;
+ continue;
+ }
+ if (!changed && statb.st_mtime != *mtp) {
+ outfmt(
+ &errout, snlfmt,
+ pathopt ? pathopt : "you have mail"
+ );
+ }
+ *mtp = statb.st_mtime;
+ }
+ changed = 0;
+ popstackmark(&smark);
+}
+
+
+void
+changemail(const char *val)
+{
+ changed++;
+}
diff --git a/usr/dash/mail.h b/usr/dash/mail.h
new file mode 100644
index 0000000..3c6b21d
--- /dev/null
+++ b/usr/dash/mail.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mail.h 8.2 (Berkeley) 5/4/95
+ */
+
+void chkmail(void);
+void changemail(const char *);
diff --git a/usr/dash/main.c b/usr/dash/main.c
new file mode 100644
index 0000000..7df3c44
--- /dev/null
+++ b/usr/dash/main.c
@@ -0,0 +1,346 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+#include "shell.h"
+#include "main.h"
+#include "mail.h"
+#include "options.h"
+#include "output.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "trap.h"
+#include "var.h"
+#include "show.h"
+#include "memalloc.h"
+#include "error.h"
+#include "init.h"
+#include "mystring.h"
+#include "exec.h"
+#include "cd.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+#define PROFILE 0
+
+int rootpid;
+int shlvl;
+#ifdef __GLIBC__
+int *dash_errno;
+#endif
+#if PROFILE
+short profile_buf[16384];
+extern int etext();
+#endif
+
+STATIC void read_profile(const char *);
+STATIC char *find_dot_file(char *);
+static int cmdloop(int);
+int main(int, char **);
+
+/*
+ * Main routine. We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands. The setjmp call sets up the location to jump to when an
+ * exception occurs. When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+main(int argc, char **argv)
+{
+ char *shinit;
+ volatile int state;
+ struct jmploc jmploc;
+ struct stackmark smark;
+ int login;
+
+#ifdef __GLIBC__
+ dash_errno = __errno_location();
+#endif
+
+#if PROFILE
+ monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+#endif
+ state = 0;
+ if (unlikely(setjmp(jmploc.loc))) {
+ int e;
+ int s;
+
+ reset();
+
+ e = exception;
+
+ s = state;
+ if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
+ exitshell();
+
+ if (e == EXINT
+#if ATTY
+ && (! attyset() || equal(termval(), "emacs"))
+#endif
+ ) {
+ out2c('\n');
+#ifdef FLUSHERR
+ flushout(out2);
+#endif
+ }
+ popstackmark(&smark);
+ FORCEINTON; /* enable interrupts */
+ if (s == 1)
+ goto state1;
+ else if (s == 2)
+ goto state2;
+ else if (s == 3)
+ goto state3;
+ else
+ goto state4;
+ }
+ handler = &jmploc;
+#ifdef DEBUG
+ opentrace();
+ trputs("Shell args: "); trargs(argv);
+#endif
+ rootpid = getpid();
+ init();
+ setstackmark(&smark);
+ login = procargs(argc, argv);
+ if (login) {
+ state = 1;
+ read_profile("/etc/profile");
+state1:
+ state = 2;
+ read_profile("$HOME/.profile");
+ }
+state2:
+ state = 3;
+ if (
+#ifndef linux
+ getuid() == geteuid() && getgid() == getegid() &&
+#endif
+ iflag
+ ) {
+ if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+ read_profile(shinit);
+ }
+ }
+ popstackmark(&smark);
+state3:
+ state = 4;
+ if (minusc)
+ evalstring(minusc, 0);
+
+ if (sflag || minusc == NULL) {
+state4: /* XXX ??? - why isn't this before the "if" statement */
+ cmdloop(1);
+ }
+#if PROFILE
+ monitor(0);
+#endif
+#if GPROF
+ {
+ extern void _mcleanup(void);
+ _mcleanup();
+ }
+#endif
+ exitshell();
+ /* NOTREACHED */
+}
+
+
+/*
+ * Read and execute commands. "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static int
+cmdloop(int top)
+{
+ union node *n;
+ struct stackmark smark;
+ int inter;
+ int status = 0;
+ int numeof = 0;
+
+ TRACE(("cmdloop(%d) called\n", top));
+#ifdef HETIO
+ if(iflag && top)
+ hetio_init();
+#endif
+ for (;;) {
+ int skip;
+
+ setstackmark(&smark);
+ if (jobctl)
+ showjobs(out2, SHOW_CHANGED);
+ inter = 0;
+ if (iflag && top) {
+ inter++;
+ chkmail();
+ }
+ n = parsecmd(inter);
+ /* showtree(n); DEBUG */
+ if (n == NEOF) {
+ if (!top || numeof >= 50)
+ break;
+ if (!stoppedjobs()) {
+ if (!Iflag)
+ break;
+ out2str("\nUse \"exit\" to leave shell.\n");
+ }
+ numeof++;
+ } else if (nflag == 0) {
+ job_warning = (job_warning == 2) ? 1 : 0;
+ numeof = 0;
+ evaltree(n, 0);
+ status = exitstatus;
+ }
+ popstackmark(&smark);
+
+ skip = evalskip;
+ if (skip) {
+ evalskip &= ~SKIPFUNC;
+ break;
+ }
+ }
+
+ return status;
+}
+
+
+
+/*
+ * Read /etc/profile or .profile. Return on error.
+ */
+
+STATIC void
+read_profile(const char *name)
+{
+ name = expandstr(name);
+ if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
+ return;
+
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+void
+readcmdfile(char *name)
+{
+ setinputfile(name, INPUT_PUSH_FILE);
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Take commands from a file. To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+
+STATIC char *
+find_dot_file(char *basename)
+{
+ char *fullname;
+ const char *path = pathval();
+ struct stat statb;
+
+ /* don't try this for absolute or relative paths */
+ if (strchr(basename, '/'))
+ return basename;
+
+ while ((fullname = padvance(&path, basename)) != NULL) {
+ if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+ /*
+ * Don't bother freeing here, since it will
+ * be freed by the caller.
+ */
+ return fullname;
+ }
+ stunalloc(fullname);
+ }
+
+ /* not found in the PATH */
+ sh_error("%s: not found", basename);
+ /* NOTREACHED */
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+ int status = 0;
+
+ if (argc >= 2) { /* That's what SVR2 does */
+ char *fullname;
+
+ fullname = find_dot_file(argv[1]);
+ setinputfile(fullname, INPUT_PUSH_FILE);
+ commandname = fullname;
+ status = cmdloop(0);
+ popfile();
+ }
+ return status;
+}
+
+
+int
+exitcmd(int argc, char **argv)
+{
+ if (stoppedjobs())
+ return 0;
+ if (argc > 1)
+ exitstatus = number(argv[1]);
+ exraise(EXEXIT);
+ /* NOTREACHED */
+}
diff --git a/usr/dash/main.h b/usr/dash/main.h
new file mode 100644
index 0000000..19e4983
--- /dev/null
+++ b/usr/dash/main.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)main.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <errno.h>
+
+/* pid of main shell */
+extern int rootpid;
+/* shell level: 0 for the main shell, 1 for its children, and so on */
+extern int shlvl;
+#define rootshell (!shlvl)
+
+#ifdef __GLIBC__
+/* glibc sucks */
+extern int *dash_errno;
+#undef errno
+#define errno (*dash_errno)
+#endif
+
+void readcmdfile(char *);
+int dotcmd(int, char **);
+int exitcmd(int, char **);
diff --git a/usr/dash/memalloc.c b/usr/dash/memalloc.c
new file mode 100644
index 0000000..d8e4413
--- /dev/null
+++ b/usr/dash/memalloc.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "shell.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+/*
+ * Like malloc, but returns an error when out of space.
+ */
+
+pointer
+ckmalloc(size_t nbytes)
+{
+ pointer p;
+
+ p = malloc(nbytes);
+ if (p == NULL)
+ sh_error("Out of space");
+ return p;
+}
+
+
+/*
+ * Same for realloc.
+ */
+
+pointer
+ckrealloc(pointer p, size_t nbytes)
+{
+ p = realloc(p, nbytes);
+ if (p == NULL)
+ sh_error("Out of space");
+ return p;
+}
+
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+char *
+savestr(const char *s)
+{
+ char *p = strdup(s);
+ if (!p)
+ sh_error("Out of space");
+ return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 504 was chosen because the Ultrix malloc handles that size
+ * well.
+ */
+
+/* minimum size of a block */
+#define MINSIZE SHELL_ALIGN(504)
+
+struct stack_block {
+ struct stack_block *prev;
+ char space[MINSIZE];
+};
+
+struct stack_block stackbase;
+struct stack_block *stackp = &stackbase;
+char *stacknxt = stackbase.space;
+size_t stacknleft = MINSIZE;
+char *sstrend = stackbase.space + MINSIZE;
+
+pointer
+stalloc(size_t nbytes)
+{
+ char *p;
+ size_t aligned;
+
+ aligned = SHELL_ALIGN(nbytes);
+ if (aligned > stacknleft) {
+ size_t len;
+ size_t blocksize;
+ struct stack_block *sp;
+
+ blocksize = aligned;
+ if (blocksize < MINSIZE)
+ blocksize = MINSIZE;
+ len = sizeof(struct stack_block) - MINSIZE + blocksize;
+ if (len < blocksize)
+ sh_error("Out of space");
+ INTOFF;
+ sp = ckmalloc(len);
+ sp->prev = stackp;
+ stacknxt = sp->space;
+ stacknleft = blocksize;
+ sstrend = stacknxt + blocksize;
+ stackp = sp;
+ INTON;
+ }
+ p = stacknxt;
+ stacknxt += aligned;
+ stacknleft -= aligned;
+ return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+#ifdef DEBUG
+ if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
+ write(2, "stunalloc\n", 10);
+ abort();
+ }
+#endif
+ stacknleft += stacknxt - (char *)p;
+ stacknxt = p;
+}
+
+
+
+void pushstackmark(struct stackmark *mark, size_t len)
+{
+ mark->stackp = stackp;
+ mark->stacknxt = stacknxt;
+ mark->stacknleft = stacknleft;
+ grabstackblock(len);
+}
+
+void setstackmark(struct stackmark *mark)
+{
+ pushstackmark(mark, stacknxt == stackp->space && stackp != &stackbase);
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+ struct stack_block *sp;
+
+ INTOFF;
+ while (stackp != mark->stackp) {
+ sp = stackp;
+ stackp = sp->prev;
+ ckfree(sp);
+ }
+ stacknxt = mark->stacknxt;
+ stacknleft = mark->stacknleft;
+ sstrend = mark->stacknxt + mark->stacknleft;
+ INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is. Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block. Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc). Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+void
+growstackblock(void)
+{
+ size_t newlen;
+
+ newlen = stacknleft * 2;
+ if (newlen < stacknleft)
+ sh_error("Out of space");
+ if (newlen < 128)
+ newlen += 128;
+
+ if (stacknxt == stackp->space && stackp != &stackbase) {
+ struct stack_block *sp;
+ struct stack_block *prevstackp;
+ size_t grosslen;
+
+ INTOFF;
+ sp = stackp;
+ prevstackp = sp->prev;
+ grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
+ sp = ckrealloc((pointer)sp, grosslen);
+ sp->prev = prevstackp;
+ stackp = sp;
+ stacknxt = sp->space;
+ stacknleft = newlen;
+ sstrend = sp->space + newlen;
+ INTON;
+ } else {
+ char *oldspace = stacknxt;
+ int oldlen = stacknleft;
+ char *p = stalloc(newlen);
+
+ /* free the space we just allocated */
+ stacknxt = memcpy(p, oldspace, oldlen);
+ stacknleft += newlen;
+ }
+}
+
+/*
+ * The following routines are somewhat easier to use than the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register. The macro STARTSTACKSTR initializes things. Then
+ * the user uses the macro STPUTC to add characters to the string. In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary. When the user is done, she can just leave the
+ * string there and refer to it using stackblock(). Or she can allocate
+ * the space for it using grabstackstr(). If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+void *
+growstackstr(void)
+{
+ size_t len = stackblocksize();
+ growstackblock();
+ return stackblock() + len;
+}
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(size_t newlen, char *p)
+{
+ size_t len = p - stacknxt;
+ size_t size;
+
+ for (;;) {
+ size_t nleft;
+
+ size = stackblocksize();
+ nleft = size - len;
+ if (nleft >= newlen)
+ break;
+ growstackblock();
+ }
+ return stackblock() + len;
+}
+
+char *
+stnputs(const char *s, size_t n, char *p)
+{
+ p = makestrspace(n, p);
+ p = mempcpy(p, s, n);
+ return p;
+}
+
+char *
+stputs(const char *s, char *p)
+{
+ return stnputs(s, strlen(s), p);
+}
diff --git a/usr/dash/memalloc.h b/usr/dash/memalloc.h
new file mode 100644
index 0000000..4b5be46
--- /dev/null
+++ b/usr/dash/memalloc.h
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <stddef.h>
+
+struct stackmark {
+ struct stack_block *stackp;
+ char *stacknxt;
+ size_t stacknleft;
+};
+
+
+extern char *stacknxt;
+extern size_t stacknleft;
+extern char *sstrend;
+
+pointer ckmalloc(size_t);
+pointer ckrealloc(pointer, size_t);
+char *savestr(const char *);
+pointer stalloc(size_t);
+void stunalloc(pointer);
+void pushstackmark(struct stackmark *mark, size_t len);
+void setstackmark(struct stackmark *);
+void popstackmark(struct stackmark *);
+void growstackblock(void);
+void *growstackstr(void);
+char *makestrspace(size_t, char *);
+char *stnputs(const char *, size_t, char *);
+char *stputs(const char *, char *);
+
+
+static inline void grabstackblock(size_t len)
+{
+ stalloc(len);
+}
+
+static inline char *_STPUTC(int c, char *p) {
+ if (p == sstrend)
+ p = growstackstr();
+ *p++ = c;
+ return p;
+}
+
+#define stackblock() ((void *)stacknxt)
+#define stackblocksize() stacknleft
+#define STARTSTACKSTR(p) ((p) = stackblock())
+#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
+#define CHECKSTRSPACE(n, p) \
+ ({ \
+ char *q = (p); \
+ size_t l = (n); \
+ size_t m = sstrend - q; \
+ if (l > m) \
+ (p) = makestrspace(l, q); \
+ 0; \
+ })
+#define USTPUTC(c, p) (*p++ = (c))
+#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p) (--p)
+#define STTOPC(p) p[-1]
+#define STADJUST(amount, p) (p += (amount))
+
+#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define stackstrend() ((void *)sstrend)
+
+#define ckfree(p) free((pointer)(p))
diff --git a/usr/dash/miscbltin.c b/usr/dash/miscbltin.c
new file mode 100644
index 0000000..09282be
--- /dev/null
+++ b/usr/dash/miscbltin.c
@@ -0,0 +1,583 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Miscelaneous builtins.
+ */
+
+#include <sys/types.h> /* quad_t */
+#include <sys/param.h> /* BSD4_4 */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <time.h> /* strtotimeval() */
+
+#include "shell.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "miscbltin.h"
+#include "mystring.h"
+#include "main.h"
+#include "expand.h"
+#include "parser.h"
+#include "trap.h"
+
+#undef rflag
+
+
+/** handle one line of the read command.
+ * more fields than variables -> remainder shall be part of last variable.
+ * less fields than variables -> remaining variables unset.
+ *
+ * @param line complete line of input
+ * @param ap argument (variable) list
+ * @param len length of line including trailing '\0'
+ */
+static void
+readcmd_handle_line(char *s, char **ap)
+{
+ struct arglist arglist;
+ struct strlist *sl;
+ char *backup;
+ char *line;
+
+ /* ifsbreakup will fiddle with stack region... */
+ line = stackblock();
+ s = grabstackstr(s);
+
+ /* need a copy, so that delimiters aren't lost
+ * in case there are more fields than variables */
+ backup = sstrdup(line);
+
+ arglist.lastp = &arglist.list;
+
+ ifsbreakup(s, &arglist);
+ *arglist.lastp = NULL;
+ ifsfree();
+
+ sl = arglist.list;
+
+ do {
+ if (!sl) {
+ /* nullify remaining arguments */
+ do {
+ setvar(*ap, nullstr, 0);
+ } while (*++ap);
+
+ return;
+ }
+
+ /* remaining fields present, but no variables left. */
+ if (!ap[1] && sl->next) {
+ size_t offset;
+ char *remainder;
+
+ /* FIXME little bit hacky, assuming that ifsbreakup
+ * will not modify the length of the string */
+ offset = sl->text - s;
+ remainder = backup + offset;
+ rmescapes(remainder);
+ setvar(*ap, remainder, 0);
+
+ return;
+ }
+
+ /* set variable to field */
+ rmescapes(sl->text);
+ setvar(*ap, sl->text, 0);
+ sl = sl->next;
+ } while (*++ap);
+}
+
+/*
+ * The read builtin. The -e option causes backslashes to escape the
+ * following character. The -p option followed by an argument prompts
+ * with the argument.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ */
+
+int
+readcmd(int argc, char **argv)
+{
+ char **ap;
+ char c;
+ int rflag;
+ char *prompt;
+ char *p;
+ int startloc;
+ int newloc;
+ int status;
+ int timeout;
+ int i;
+ fd_set set;
+ struct timeval ts, t0, t1, to;
+
+ ts.tv_sec = ts.tv_usec = 0;
+
+ rflag = 0;
+ timeout = 0;
+ prompt = NULL;
+ while ((i = nextopt("p:rt:")) != '\0') {
+ switch(i) {
+ case 'p':
+ prompt = optionarg;
+ break;
+ case 't':
+ p = strtotimeval(optionarg, &ts);
+ if (*p || (!ts.tv_sec && !ts.tv_usec))
+ sh_error("invalid timeout");
+ timeout = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ if (prompt && isatty(0)) {
+ out2str(prompt);
+#ifdef FLUSHERR
+ flushall();
+#endif
+ }
+ if (*(ap = argptr) == NULL)
+ sh_error("arg count");
+
+ status = 0;
+ if (timeout) {
+ gettimeofday(&t0, NULL);
+
+ /* ts += t0; */
+ ts.tv_usec += t0.tv_usec;
+ while (ts.tv_usec >= 1000000) {
+ ts.tv_sec++;
+ ts.tv_usec -= 1000000;
+ }
+ ts.tv_sec += t0.tv_sec;
+ }
+ STARTSTACKSTR(p);
+
+ goto start;
+
+ for (;;) {
+ if (timeout) {
+ gettimeofday(&t1, NULL);
+ if (t1.tv_sec > ts.tv_sec ||
+ (t1.tv_sec == ts.tv_sec &&
+ t1.tv_usec >= ts.tv_usec)) {
+ status = 1;
+ break; /* Timeout! */
+ }
+
+ /* to = ts - t1; */
+ if (ts.tv_usec >= t1.tv_usec) {
+ to.tv_usec = ts.tv_usec - t1.tv_usec;
+ to.tv_sec = ts.tv_sec - t1.tv_sec;
+ } else {
+ to.tv_usec = ts.tv_usec - t1.tv_usec + 1000000;
+ to.tv_sec = ts.tv_sec - t1.tv_sec - 1;
+ }
+
+ FD_ZERO(&set);
+ FD_SET(0, &set);
+ if (select(1, &set, NULL, NULL, &to) != 1) {
+ status = 1;
+ break; /* Timeout! */
+ }
+ }
+ switch (read(0, &c, 1)) {
+ case 1:
+ break;
+ default:
+ if (errno == EINTR && !pendingsigs)
+ continue;
+ /* fall through */
+ case 0:
+ status = 1;
+ goto out;
+ }
+ if (c == '\0')
+ continue;
+ if (newloc >= startloc) {
+ if (c == '\n')
+ goto resetbs;
+ goto put;
+ }
+ if (!rflag && c == '\\') {
+ newloc = p - (char *)stackblock();
+ continue;
+ }
+ if (c == '\n')
+ break;
+put:
+ CHECKSTRSPACE(2, p);
+ if (strchr(qchars, c))
+ USTPUTC(CTLESC, p);
+ USTPUTC(c, p);
+
+ if (newloc >= startloc) {
+resetbs:
+ recordregion(startloc, newloc, 0);
+start:
+ startloc = p - (char *)stackblock();
+ newloc = startloc - 1;
+ }
+ }
+out:
+ recordregion(startloc, p - (char *)stackblock(), 0);
+ STACKSTRNUL(p);
+ readcmd_handle_line(p + 1, ap);
+ return status;
+}
+
+
+
+/*
+ * umask builtin
+ *
+ * This code was ripped from pdksh 5.2.14 and hacked for use with
+ * dash by Herbert Xu.
+ *
+ * Public domain.
+ */
+
+int
+umaskcmd(int argc, char **argv)
+{
+ char *ap;
+ int mask;
+ int i;
+ int symbolic_mode = 0;
+
+ while ((i = nextopt("S")) != '\0') {
+ symbolic_mode = 1;
+ }
+
+ INTOFF;
+ mask = umask(0);
+ umask(mask);
+ INTON;
+
+ if ((ap = *argptr) == NULL) {
+ if (symbolic_mode) {
+ char buf[18];
+ int j;
+
+ mask = ~mask;
+ ap = buf;
+ for (i = 0; i < 3; i++) {
+ *ap++ = "ugo"[i];
+ *ap++ = '=';
+ for (j = 0; j < 3; j++)
+ if (mask & (1 << (8 - (3*i + j))))
+ *ap++ = "rwx"[j];
+ *ap++ = ',';
+ }
+ ap[-1] = '\0';
+ out1fmt("%s\n", buf);
+ } else {
+ out1fmt("%.4o\n", mask);
+ }
+ } else {
+ int new_mask;
+
+ if (isdigit((unsigned char) *ap)) {
+ new_mask = 0;
+ do {
+ if (*ap >= '8' || *ap < '0')
+ sh_error(illnum, *argptr);
+ new_mask = (new_mask << 3) + (*ap - '0');
+ } while (*++ap != '\0');
+ } else {
+ int positions, new_val;
+ char op;
+
+ mask = ~mask;
+ new_mask = mask;
+ positions = 0;
+ while (*ap) {
+ while (*ap && strchr("augo", *ap))
+ switch (*ap++) {
+ case 'a': positions |= 0111; break;
+ case 'u': positions |= 0100; break;
+ case 'g': positions |= 0010; break;
+ case 'o': positions |= 0001; break;
+ }
+ if (!positions)
+ positions = 0111; /* default is a */
+ if (!strchr("=+-", op = *ap))
+ break;
+ ap++;
+ new_val = 0;
+ while (*ap && strchr("rwxugoXs", *ap))
+ switch (*ap++) {
+ case 'r': new_val |= 04; break;
+ case 'w': new_val |= 02; break;
+ case 'x': new_val |= 01; break;
+ case 'u': new_val |= mask >> 6;
+ break;
+ case 'g': new_val |= mask >> 3;
+ break;
+ case 'o': new_val |= mask >> 0;
+ break;
+ case 'X': if (mask & 0111)
+ new_val |= 01;
+ break;
+ case 's': /* ignored */
+ break;
+ }
+ new_val = (new_val & 07) * positions;
+ switch (op) {
+ case '-':
+ new_mask &= ~new_val;
+ break;
+ case '=':
+ new_mask = new_val
+ | (new_mask & ~(positions * 07));
+ break;
+ case '+':
+ new_mask |= new_val;
+ }
+ if (*ap == ',') {
+ positions = 0;
+ ap++;
+ } else if (!strchr("=+-", *ap))
+ break;
+ }
+ if (*ap) {
+ sh_error("Illegal mode: %s", *argptr);
+ return 1;
+ }
+ new_mask = ~new_mask;
+ }
+ umask(new_mask);
+ }
+ return 0;
+}
+
+#ifdef HAVE_GETRLIMIT
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+ const char *name;
+ int cmd;
+ int factor; /* multiply by to get rlim_{cur,max} values */
+ char option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+ { "time(seconds)", RLIMIT_CPU, 1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+ { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+ { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+ { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
+#endif
+#ifdef RLIMIT_CORE
+ { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+ { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+ { "process", RLIMIT_NPROC, 1, 'p' },
+#endif
+#ifdef RLIMIT_NOFILE
+ { "nofiles", RLIMIT_NOFILE, 1, 'n' },
+#endif
+#ifdef RLIMIT_AS
+ { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
+#endif
+#ifdef RLIMIT_LOCKS
+ { "locks", RLIMIT_LOCKS, 1, 'w' },
+#endif
+#ifdef RLIMIT_RTPRIO
+ { "rtprio", RLIMIT_RTPRIO, 1, 'r' },
+#endif
+ { (char *) 0, 0, 0, '\0' }
+};
+
+enum limtype { SOFT = 0x1, HARD = 0x2 };
+
+static void printlim(enum limtype how, const struct rlimit *limit,
+ const struct limits *l)
+{
+ rlim_t val;
+
+ val = limit->rlim_max;
+ if (how & SOFT)
+ val = limit->rlim_cur;
+
+ if (val == RLIM_INFINITY)
+ out1fmt("unlimited\n");
+ else {
+ val /= l->factor;
+ out1fmt("%" PRIdMAX "\n", (intmax_t) val);
+ }
+}
+
+int
+ulimitcmd(int argc, char **argv)
+{
+ int c;
+ rlim_t val = 0;
+ enum limtype how = SOFT | HARD;
+ const struct limits *l;
+ int set, all = 0;
+ int optc, what;
+ struct rlimit limit;
+
+ what = 'f';
+ while ((optc = nextopt("HSa"
+#ifdef RLIMIT_CPU
+ "t"
+#endif
+#ifdef RLIMIT_FSIZE
+ "f"
+#endif
+#ifdef RLIMIT_DATA
+ "d"
+#endif
+#ifdef RLIMIT_STACK
+ "s"
+#endif
+#ifdef RLIMIT_CORE
+ "c"
+#endif
+#ifdef RLIMIT_RSS
+ "m"
+#endif
+#ifdef RLIMIT_MEMLOCK
+ "l"
+#endif
+#ifdef RLIMIT_NPROC
+ "p"
+#endif
+#ifdef RLIMIT_NOFILE
+ "n"
+#endif
+#ifdef RLIMIT_AS
+ "v"
+#endif
+#ifdef RLIMIT_LOCKS
+ "w"
+#endif
+ )) != '\0')
+ switch (optc) {
+ case 'H':
+ how = HARD;
+ break;
+ case 'S':
+ how = SOFT;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ default:
+ what = optc;
+ }
+
+ for (l = limits; l->option != what; l++)
+ ;
+
+ set = *argptr ? 1 : 0;
+ if (set) {
+ char *p = *argptr;
+
+ if (all || argptr[1])
+ sh_error("too many arguments");
+ if (strcmp(p, "unlimited") == 0)
+ val = RLIM_INFINITY;
+ else {
+ val = (rlim_t) 0;
+
+ while ((c = *p++) >= '0' && c <= '9')
+ {
+ val = (val * 10) + (long)(c - '0');
+ if (val < (rlim_t) 0)
+ break;
+ }
+ if (c)
+ sh_error("bad number");
+ val *= l->factor;
+ }
+ }
+ if (all) {
+ for (l = limits; l->name; l++) {
+ getrlimit(l->cmd, &limit);
+ out1fmt("%-20s ", l->name);
+ printlim(how, &limit, l);
+ }
+ return 0;
+ }
+
+ getrlimit(l->cmd, &limit);
+ if (set) {
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (setrlimit(l->cmd, &limit) < 0)
+ sh_error("error setting limit (%s)", strerror(errno));
+ } else {
+ printlim(how, &limit, l);
+ }
+ return 0;
+}
+#endif
diff --git a/usr/dash/miscbltin.h b/usr/dash/miscbltin.h
new file mode 100644
index 0000000..dd9a8d1
--- /dev/null
+++ b/usr/dash/miscbltin.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1997 Christos Zoulas. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.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. 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.
+ */
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
diff --git a/usr/dash/mkbuiltins b/usr/dash/mkbuiltins
new file mode 100644
index 0000000..94b36b9
--- /dev/null
+++ b/usr/dash/mkbuiltins
@@ -0,0 +1,115 @@
+#!/bin/sh -
+# $NetBSD: mkbuiltins,v 1.17 2002/11/24 22:35:41 christos Exp $
+#
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
+
+tempfile=mktemp
+if ! type tempfile > /dev/null 2>&1 && ! type mktemp > /dev/null 2>&1; then
+ _my_tempfile()
+ {
+ local index=0
+ while test -f "${TMPDIR:-/tmp}/builtin.$$.$index"; do
+ index=`expr $index + 1`
+ done
+
+ touch "${TMPDIR:-/tmp}/builtin.$$.$index"
+ echo "${TMPDIR:-/tmp}/builtin.$$.$index"
+ }
+
+ tempfile="_my_tempfile"
+elif ! type tempfile > /dev/null 2>&1; then
+ tempfile="mktemp ${TMPDIR:-/tmp}/builtin.XXXXXX"
+fi
+
+trap 'rm -f $temp $temp2' EXIT
+temp=$($tempfile)
+temp2=$($tempfile)
+
+builtins=$1
+
+exec > builtins.c
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include "shell.h"
+#include "builtins.h"
+
+!
+< $builtins sed '/^#/d; /^$/d' > $temp
+awk '{ printf "int %s(int, char **);\n", $1}' $temp
+echo '
+const struct builtincmd builtincmd[] = {'
+awk '{ for (i = 2 ; i <= NF ; i++) {
+ line = $i "\t" $1
+ if ($i ~ /^-/)
+ line = $(++i) "\t" line
+ print line
+ }}' $temp | LC_ALL=C sort -k 1,1 | tee $temp2 | awk '{
+ opt = ""
+ if (NF > 2) {
+ opt = substr($2, 2)
+ $2 = $3
+ }
+ printf "\t{ \"%s\", %s, %d },\n", $1,
+ (opt ~ /n/) ? "NULL" : $2,
+ (opt ~ /s/) + (opt ~ /[su]/) * 2 + (opt ~ /a/) * 4
+ }'
+echo '};'
+
+exec > builtins.h
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+!
+sed 's/ -[a-z]*//' $temp2 | nl -b a -v 0 | LC_COLLATE=C sort -u -k 3,3 |
+tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
+ awk '{ printf "#define %s (builtincmd + %d)\n", $3, $1}'
+printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2)
+echo '
+#define BUILTIN_SPECIAL 0x1
+#define BUILTIN_REGULAR 0x2
+#define BUILTIN_ASSIGN 0x4
+
+struct builtincmd {
+ const char *name;
+ int (*builtin)(int, char **);
+ unsigned flags;
+};
+
+extern const struct builtincmd builtincmd[];'
diff --git a/usr/dash/mkinit.c b/usr/dash/mkinit.c
new file mode 100644
index 0000000..9714bee
--- /dev/null
+++ b/usr/dash/mkinit.c
@@ -0,0 +1,479 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 program scans all the source files for code to handle various
+ * special events and combines this code into one file. This (allegedly)
+ * improves the structure of the program since there is no need for
+ * anyone outside of a module to know that that module performs special
+ * operations on particular events.
+ *
+ * Usage: mkinit sourcefile...
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/*
+ * OUTFILE is the name of the output file. Output is initially written
+ * to the file OUTTEMP, which is then moved to OUTFILE.
+ */
+
+#define OUTFILE "init.c"
+#define OUTTEMP "init.c.new"
+
+
+/*
+ * A text structure is basicly just a string that grows as more characters
+ * are added onto the end of it. It is implemented as a linked list of
+ * blocks of characters. The routines addstr and addchar append a string
+ * or a single character, respectively, to a text structure. Writetext
+ * writes the contents of a text structure to a file.
+ */
+
+#define BLOCKSIZE 512
+
+struct text {
+ char *nextc;
+ int nleft;
+ struct block *start;
+ struct block *last;
+};
+
+struct block {
+ struct block *next;
+ char text[BLOCKSIZE];
+};
+
+
+/*
+ * There is one event structure for each event that mkinit handles.
+ */
+
+struct event {
+ char *name; /* name of event (e.g. INIT) */
+ char *routine; /* name of routine called on event */
+ char *comment; /* comment describing routine */
+ struct text code; /* code for handling event */
+};
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mkinit program.\n\
+ */\n\
+\n";
+
+char init[] = "\
+/*\n\
+ * Initialization code.\n\
+ */\n";
+
+char reset[] = "\
+/*\n\
+ * This routine is called when an error or an interrupt occurs in an\n\
+ * interactive shell and control is returned to the main command loop.\n\
+ */\n";
+
+
+struct event event[] = {
+ {"INIT", "init", init},
+ {"RESET", "reset", reset},
+ {NULL, NULL}
+};
+
+
+char *curfile; /* current file */
+int linno; /* current line */
+char *header_files[200]; /* list of header files */
+struct text defines; /* #define statements */
+struct text decls; /* declarations */
+int amiddecls; /* for formatting */
+
+
+void readfile(char *);
+int match(char *, char *);
+int gooddefine(char *);
+void doevent(struct event *, FILE *, char *);
+void doinclude(char *);
+void dodecl(char *, FILE *);
+void output(void);
+void addstr(char *, struct text *);
+void addchar(int, struct text *);
+void writetext(struct text *, FILE *);
+FILE *ckfopen(char *, char *);
+void *ckmalloc(int);
+char *savestr(char *);
+static void error(char *);
+int main(int, char **);
+
+#define equal(s1, s2) (strcmp(s1, s2) == 0)
+
+int
+main(int argc, char **argv)
+{
+ char **ap;
+
+ header_files[0] = "\"shell.h\"";
+ header_files[1] = "\"mystring.h\"";
+ header_files[2] = "\"init.h\"";
+ for (ap = argv + 1 ; *ap ; ap++)
+ readfile(*ap);
+ output();
+ rename(OUTTEMP, OUTFILE);
+ exit(0);
+ /* NOTREACHED */
+}
+
+
+/*
+ * Parse an input file.
+ */
+
+void
+readfile(char *fname)
+{
+ FILE *fp;
+ char line[1024];
+ struct event *ep;
+
+ fp = ckfopen(fname, "r");
+ curfile = fname;
+ linno = 0;
+ amiddecls = 0;
+ while (fgets(line, sizeof line, fp) != NULL) {
+ linno++;
+ for (ep = event ; ep->name ; ep++) {
+ if (line[0] == ep->name[0] && match(ep->name, line)) {
+ doevent(ep, fp, fname);
+ break;
+ }
+ }
+ if (line[0] == 'I' && match("INCLUDE", line))
+ doinclude(line);
+ if (line[0] == 'M' && match("MKINIT", line))
+ dodecl(line, fp);
+ if (line[0] == '#' && gooddefine(line)) {
+ char *cp;
+ char line2[1024];
+ static const char undef[] = "#undef ";
+
+ strcpy(line2, line);
+ memcpy(line2, undef, sizeof(undef) - 1);
+ cp = line2 + sizeof(undef) - 1;
+ while(*cp && (*cp == ' ' || *cp == '\t'))
+ cp++;
+ while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp++ = '\n'; *cp = '\0';
+ addstr(line2, &defines);
+ addstr(line, &defines);
+ }
+ }
+ fclose(fp);
+}
+
+
+int
+match(char *name, char *line)
+{
+ char *p, *q;
+
+ p = name, q = line;
+ while (*p) {
+ if (*p++ != *q++)
+ return 0;
+ }
+ if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
+ return 0;
+ return 1;
+}
+
+
+int
+gooddefine(char *line)
+{
+ char *p;
+
+ if (! match("#define", line))
+ return 0; /* not a define */
+ p = line + 7;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ while (*p != ' ' && *p != '\t') {
+ if (*p == '(')
+ return 0; /* macro definition */
+ p++;
+ }
+ while (*p != '\n' && *p != '\0')
+ p++;
+ if (p[-1] == '\\')
+ return 0; /* multi-line definition */
+ return 1;
+}
+
+
+void
+doevent(struct event *ep, FILE *fp, char *fname)
+{
+ char line[1024];
+ int indent;
+ char *p;
+
+ sprintf(line, "\n /* from %s: */\n", fname);
+ addstr(line, &ep->code);
+ addstr(" {\n", &ep->code);
+ for (;;) {
+ linno++;
+ if (fgets(line, sizeof line, fp) == NULL)
+ error("Unexpected EOF");
+ if (equal(line, "}\n"))
+ break;
+ indent = 6;
+ for (p = line ; *p == '\t' ; p++)
+ indent += 8;
+ for ( ; *p == ' ' ; p++)
+ indent++;
+ if (*p == '\n' || *p == '#')
+ indent = 0;
+ while (indent >= 8) {
+ addchar('\t', &ep->code);
+ indent -= 8;
+ }
+ while (indent > 0) {
+ addchar(' ', &ep->code);
+ indent--;
+ }
+ addstr(p, &ep->code);
+ }
+ addstr(" }\n", &ep->code);
+}
+
+
+void
+doinclude(char *line)
+{
+ char *p;
+ char *name;
+ char **pp;
+
+ for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
+ if (*p == '\0')
+ error("Expecting '\"' or '<'");
+ name = p;
+ while (*p != ' ' && *p != '\t' && *p != '\n')
+ p++;
+ if (p[-1] != '"' && p[-1] != '>')
+ error("Missing terminator");
+ *p = '\0';
+
+ /* name now contains the name of the include file */
+ for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
+ if (*pp == NULL)
+ *pp = savestr(name);
+}
+
+
+void
+dodecl(char *line1, FILE *fp)
+{
+ char line[1024];
+ char *p, *q;
+
+ if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
+ addchar('\n', &decls);
+ do {
+ linno++;
+ if (fgets(line, sizeof line, fp) == NULL)
+ error("Unterminated structure declaration");
+ addstr(line, &decls);
+ } while (line[0] != '}');
+ amiddecls = 0;
+ } else {
+ if (! amiddecls)
+ addchar('\n', &decls);
+ q = NULL;
+ for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
+ continue;
+ if (*p == '=') { /* eliminate initialization */
+ for (q = p ; *q && *q != ';' ; q++);
+ if (*q == '\0')
+ q = NULL;
+ else {
+ while (p[-1] == ' ')
+ p--;
+ *p = '\0';
+ }
+ }
+ addstr("extern", &decls);
+ addstr(line1 + 6, &decls);
+ if (q != NULL)
+ addstr(q, &decls);
+ amiddecls = 1;
+ }
+}
+
+
+
+/*
+ * Write the output to the file OUTTEMP.
+ */
+
+void
+output(void)
+{
+ FILE *fp;
+ char **pp;
+ struct event *ep;
+
+ fp = ckfopen(OUTTEMP, "w");
+ fputs(writer, fp);
+ for (pp = header_files ; *pp ; pp++)
+ fprintf(fp, "#include %s\n", *pp);
+ fputs("\n\n\n", fp);
+ writetext(&defines, fp);
+ fputs("\n\n", fp);
+ writetext(&decls, fp);
+ for (ep = event ; ep->name ; ep++) {
+ fputs("\n\n\n", fp);
+ fputs(ep->comment, fp);
+ fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
+ writetext(&ep->code, fp);
+ fprintf(fp, "}\n");
+ }
+ fclose(fp);
+}
+
+
+/*
+ * A text structure is simply a block of text that is kept in memory.
+ * Addstr appends a string to the text struct, and addchar appends a single
+ * character.
+ */
+
+void
+addstr(char *s, struct text *text)
+{
+ while (*s) {
+ if (--text->nleft < 0)
+ addchar(*s++, text);
+ else
+ *text->nextc++ = *s++;
+ }
+}
+
+
+void
+addchar(int c, struct text *text)
+{
+ struct block *bp;
+
+ if (--text->nleft < 0) {
+ bp = ckmalloc(sizeof *bp);
+ if (text->start == NULL)
+ text->start = bp;
+ else
+ text->last->next = bp;
+ text->last = bp;
+ text->nextc = bp->text;
+ text->nleft = BLOCKSIZE - 1;
+ }
+ *text->nextc++ = c;
+}
+
+/*
+ * Write the contents of a text structure to a file.
+ */
+void
+writetext(struct text *text, FILE *fp)
+{
+ struct block *bp;
+
+ if (text->start != NULL) {
+ for (bp = text->start ; bp != text->last ; bp = bp->next) {
+ if ((fwrite(bp->text, sizeof (char), BLOCKSIZE, fp)) != BLOCKSIZE)
+ error("Can't write data\n");
+ }
+ if ((fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp)) != (BLOCKSIZE - text->nleft))
+ error("Can't write data\n");
+ }
+}
+
+FILE *
+ckfopen(char *file, char *mode)
+{
+ FILE *fp;
+
+ if ((fp = fopen(file, mode)) == NULL) {
+ fprintf(stderr, "Can't open %s\n", file);
+ exit(2);
+ }
+ return fp;
+}
+
+void *
+ckmalloc(int nbytes)
+{
+ char *p;
+
+ if ((p = malloc(nbytes)) == NULL)
+ error("Out of space");
+ return p;
+}
+
+char *
+savestr(char *s)
+{
+ char *p;
+
+ p = ckmalloc(strlen(s) + 1);
+ strcpy(p, s);
+ return p;
+}
+
+static void
+error(char *msg)
+{
+ if (curfile != NULL)
+ fprintf(stderr, "%s:%d: ", curfile, linno);
+ fprintf(stderr, "%s\n", msg);
+ exit(2);
+ /* NOTREACHED */
+}
diff --git a/usr/dash/mknodes.c b/usr/dash/mknodes.c
new file mode 100644
index 0000000..1903a60
--- /dev/null
+++ b/usr/dash/mknodes.c
@@ -0,0 +1,448 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 program reads the nodetypes file and nodes.c.pat file. It generates
+ * the files nodes.h and nodes.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define MAXTYPES 50 /* max number of node types */
+#define MAXFIELDS 20 /* max fields in a structure */
+#define BUFLEN 100 /* size of character buffers */
+
+/* field types */
+#define T_NODE 1 /* union node *field */
+#define T_NODELIST 2 /* struct nodelist *field */
+#define T_STRING 3
+#define T_INT 4 /* int field */
+#define T_OTHER 5 /* other */
+#define T_TEMP 6 /* don't copy this field */
+
+
+struct field { /* a structure field */
+ char *name; /* name of field */
+ int type; /* type of field */
+ char *decl; /* declaration of field */
+};
+
+
+struct str { /* struct representing a node structure */
+ char *tag; /* structure tag */
+ int nfields; /* number of fields in the structure */
+ struct field field[MAXFIELDS]; /* the fields of the structure */
+ int done; /* set if fully parsed */
+};
+
+
+static int ntypes; /* number of node types */
+static char *nodename[MAXTYPES]; /* names of the nodes */
+static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
+static int nstr; /* number of structures */
+static struct str str[MAXTYPES]; /* the structures */
+static struct str *curstr; /* current structure */
+static FILE *infp;
+static char line[1024];
+static int linno;
+static char *linep;
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(void);
+static void error(const char *, ...);
+static char *savestr(const char *);
+int main(int, char **);
+
+
+int
+main(int argc, char **argv)
+{
+
+ /*
+ * some versions of linux complain: initializer element is not
+ * constant if this is done at compile time.
+ */
+ infp = stdin;
+
+ if (argc != 3)
+ error("usage: mknodes file");
+ if ((infp = fopen(argv[1], "r")) == NULL)
+ error("Can't open %s", argv[1]);
+ while (readline()) {
+ if (line[0] == ' ' || line[0] == '\t')
+ parsefield();
+ else if (line[0] != '\0')
+ parsenode();
+ }
+ output(argv[2]);
+ exit(0);
+ /* NOTREACHED */
+}
+
+
+
+static void
+parsenode(void)
+{
+ char name[BUFLEN];
+ char tag[BUFLEN];
+ struct str *sp;
+
+ if (curstr && curstr->nfields > 0)
+ curstr->done = 1;
+ nextfield(name);
+ if (! nextfield(tag))
+ error("Tag expected");
+ if (*linep != '\0')
+ error("Garbage at end of line");
+ nodename[ntypes] = savestr(name);
+ for (sp = str ; sp < str + nstr ; sp++) {
+ if (strcmp(sp->tag, tag) == 0)
+ break;
+ }
+ if (sp >= str + nstr) {
+ sp->tag = savestr(tag);
+ sp->nfields = 0;
+ curstr = sp;
+ nstr++;
+ }
+ nodestr[ntypes] = sp;
+ ntypes++;
+}
+
+
+static void
+parsefield(void)
+{
+ char name[BUFLEN];
+ char type[BUFLEN];
+ char decl[2 * BUFLEN];
+ struct field *fp;
+
+ if (curstr == NULL || curstr->done)
+ error("No current structure to add field to");
+ if (! nextfield(name))
+ error("No field name");
+ if (! nextfield(type))
+ error("No field type");
+ fp = &curstr->field[curstr->nfields];
+ fp->name = savestr(name);
+ if (strcmp(type, "nodeptr") == 0) {
+ fp->type = T_NODE;
+ sprintf(decl, "union node *%s", name);
+ } else if (strcmp(type, "nodelist") == 0) {
+ fp->type = T_NODELIST;
+ sprintf(decl, "struct nodelist *%s", name);
+ } else if (strcmp(type, "string") == 0) {
+ fp->type = T_STRING;
+ sprintf(decl, "char *%s", name);
+ } else if (strcmp(type, "int") == 0) {
+ fp->type = T_INT;
+ sprintf(decl, "int %s", name);
+ } else if (strcmp(type, "other") == 0) {
+ fp->type = T_OTHER;
+ } else if (strcmp(type, "temp") == 0) {
+ fp->type = T_TEMP;
+ } else {
+ error("Unknown type %s", type);
+ }
+ if (fp->type == T_OTHER || fp->type == T_TEMP) {
+ skipbl();
+ fp->decl = savestr(linep);
+ } else {
+ if (*linep)
+ error("Garbage at end of line");
+ fp->decl = savestr(decl);
+ }
+ curstr->nfields++;
+}
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mknodes program.\n\
+ */\n\
+\n";
+
+static void
+output(char *file)
+{
+ FILE *hfile;
+ FILE *cfile;
+ FILE *patfile;
+ int i;
+ struct str *sp;
+ struct field *fp;
+ char *p;
+
+ if ((patfile = fopen(file, "r")) == NULL)
+ error("Can't open %s", file);
+ if ((hfile = fopen("nodes.h", "w")) == NULL)
+ error("Can't create nodes.h");
+ if ((cfile = fopen("nodes.c", "w")) == NULL)
+ error("Can't create nodes.c");
+ fputs(writer, hfile);
+ for (i = 0 ; i < ntypes ; i++)
+ fprintf(hfile, "#define %s %d\n", nodename[i], i);
+ fputs("\n\n\n", hfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, "struct %s {\n", sp->tag);
+ for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
+ fprintf(hfile, " %s;\n", fp->decl);
+ }
+ fputs("};\n\n\n", hfile);
+ }
+ fputs("union node {\n", hfile);
+ fprintf(hfile, " int type;\n");
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag);
+ }
+ fputs("};\n\n\n", hfile);
+ fputs("struct nodelist {\n", hfile);
+ fputs("\tstruct nodelist *next;\n", hfile);
+ fputs("\tunion node *n;\n", hfile);
+ fputs("};\n\n\n", hfile);
+ fputs("struct funcnode {\n", hfile);
+ fputs("\tint count;\n", hfile);
+ fputs("\tunion node n;\n", hfile);
+ fputs("};\n\n\n", hfile);
+ fputs("struct funcnode *copyfunc(union node *);\n", hfile);
+ fputs("void freefunc(struct funcnode *);\n", hfile);
+
+ fputs(writer, cfile);
+ while (fgets(line, sizeof line, patfile) != NULL) {
+ for (p = line ; *p == ' ' || *p == '\t' ; p++);
+ if (strcmp(p, "%SIZES\n") == 0)
+ outsizes(cfile);
+ else if (strcmp(p, "%CALCSIZE\n") == 0)
+ outfunc(cfile, 1);
+ else if (strcmp(p, "%COPY\n") == 0)
+ outfunc(cfile, 0);
+ else
+ fputs(line, cfile);
+ }
+}
+
+
+
+static void
+outsizes(FILE *cfile)
+{
+ int i;
+
+ fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
+ for (i = 0 ; i < ntypes ; i++) {
+ fprintf(cfile, " SHELL_ALIGN(sizeof (struct %s)),\n",
+ nodestr[i]->tag);
+ }
+ fprintf(cfile, "};\n");
+}
+
+
+static void
+outfunc(FILE *cfile, int calcsize)
+{
+ struct str *sp;
+ struct field *fp;
+ int i;
+
+ fputs(" if (n == NULL)\n", cfile);
+ if (calcsize)
+ fputs(" return;\n", cfile);
+ else
+ fputs(" return NULL;\n", cfile);
+ if (calcsize)
+ fputs(" funcblocksize += nodesize[n->type];\n", cfile);
+ else {
+ fputs(" new = funcblock;\n", cfile);
+ fputs(" funcblock = (char *) funcblock + nodesize[n->type];\n", cfile);
+ }
+ fputs(" switch (n->type) {\n", cfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ for (i = 0 ; i < ntypes ; i++) {
+ if (nodestr[i] == sp)
+ fprintf(cfile, " case %s:\n", nodename[i]);
+ }
+ for (i = sp->nfields ; --i >= 1 ; ) {
+ fp = &sp->field[i];
+ switch (fp->type) {
+ case T_NODE:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "calcsize(n->%s.%s);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_NODELIST:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "sizenodelist(n->%s.%s);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_STRING:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_INT:
+ case T_OTHER:
+ if (! calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ }
+ }
+ indent(12, cfile);
+ fputs("break;\n", cfile);
+ }
+ fputs(" };\n", cfile);
+ if (! calcsize)
+ fputs(" new->type = n->type;\n", cfile);
+}
+
+
+static void
+indent(int amount, FILE *fp)
+{
+ while (amount >= 8) {
+ putc('\t', fp);
+ amount -= 8;
+ }
+ while (--amount >= 0) {
+ putc(' ', fp);
+ }
+}
+
+
+static int
+nextfield(char *buf)
+{
+ char *p, *q;
+
+ p = linep;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ q = buf;
+ while (*p != ' ' && *p != '\t' && *p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ linep = p;
+ return (q > buf);
+}
+
+
+static void
+skipbl(void)
+{
+ while (*linep == ' ' || *linep == '\t')
+ linep++;
+}
+
+
+static int
+readline(void)
+{
+ char *p;
+
+ if (fgets(line, 1024, infp) == NULL)
+ return 0;
+ for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
+ while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+ p--;
+ *p = '\0';
+ linep = line;
+ linno++;
+ if (p - line > BUFLEN)
+ error("Line too long");
+ return 1;
+}
+
+
+
+static void
+error(const char *msg, ...)
+{
+ va_list va;
+
+ va_start(va, msg);
+
+ (void) fprintf(stderr, "line %d: ", linno);
+ (void) vfprintf(stderr, msg, va);
+ (void) fputc('\n', stderr);
+
+ va_end(va);
+
+ exit(2);
+ /* NOTREACHED */
+}
+
+
+
+static char *
+savestr(const char *s)
+{
+ char *p;
+
+ if ((p = malloc(strlen(s) + 1)) == NULL)
+ error("Out of space");
+ (void) strcpy(p, s);
+ return p;
+}
diff --git a/usr/dash/mksyntax.c b/usr/dash/mksyntax.c
new file mode 100644
index 0000000..a23c18c
--- /dev/null
+++ b/usr/dash/mksyntax.c
@@ -0,0 +1,315 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 program creates syntax.h and syntax.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include "parser.h"
+
+
+struct synclass {
+ char *name;
+ char *comment;
+};
+
+/* Syntax classes */
+struct synclass synclass[] = {
+ { "CWORD", "character is nothing special" },
+ { "CNL", "newline character" },
+ { "CBACK", "a backslash character" },
+ { "CSQUOTE", "single quote" },
+ { "CDQUOTE", "double quote" },
+ { "CENDQUOTE", "a terminating quote" },
+ { "CBQUOTE", "backwards single quote" },
+ { "CVAR", "a dollar sign" },
+ { "CENDVAR", "a '}' character" },
+ { "CLP", "a left paren in arithmetic" },
+ { "CRP", "a right paren in arithmetic" },
+ { "CEOF", "end of file" },
+ { "CCTL", "like CWORD, except it must be escaped" },
+ { "CSPCL", "these terminate a word" },
+ { "CIGN", "character should be ignored" },
+ { NULL, NULL }
+};
+
+
+/*
+ * Syntax classes for is_ functions. Warning: if you add new classes
+ * you may have to change the definition of the is_in_name macro.
+ */
+struct synclass is_entry[] = {
+ { "ISDIGIT", "a digit" },
+ { "ISUPPER", "an upper case letter" },
+ { "ISLOWER", "a lower case letter" },
+ { "ISUNDER", "an underscore" },
+ { "ISSPECL", "the name of a special parameter" },
+ { NULL, NULL }
+};
+
+static char writer[] = "\
+/*\n\
+ * This file was generated by the mksyntax program.\n\
+ */\n\
+\n";
+
+
+static FILE *cfile;
+static FILE *hfile;
+static char *syntax[513];
+
+static void filltable(char *);
+static void init(void);
+static void add(char *, char *);
+static void print(char *);
+static void output_type_macros(void);
+int main(int, char **);
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ char buf[80];
+ int pos;
+
+ /* Create output files */
+ if ((cfile = fopen("syntax.c", "w")) == NULL) {
+ perror("syntax.c");
+ exit(2);
+ }
+ if ((hfile = fopen("syntax.h", "w")) == NULL) {
+ perror("syntax.h");
+ exit(2);
+ }
+ fputs(writer, hfile);
+ fputs(writer, cfile);
+
+ fputs("#include <ctype.h>\n", hfile);
+ fputs("\n", hfile);
+ fputs("#ifdef CEOF\n", hfile);
+ fputs("#undef CEOF\n", hfile);
+ fputs("#endif\n", hfile);
+ fputs("\n", hfile);
+
+ /* Generate the #define statements in the header file */
+ fputs("/* Syntax classes */\n", hfile);
+ for (i = 0 ; synclass[i].name ; i++) {
+ sprintf(buf, "#define %s %d", synclass[i].name, i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", synclass[i].comment);
+ }
+ putc('\n', hfile);
+ fputs("/* Syntax classes for is_ functions */\n", hfile);
+ for (i = 0 ; is_entry[i].name ; i++) {
+ sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", is_entry[i].comment);
+ }
+ putc('\n', hfile);
+ fprintf(hfile, "#define SYNBASE %d\n", 130);
+ fprintf(hfile, "#define PEOF %d\n\n", -130);
+ fprintf(hfile, "#define PEOA %d\n\n", -129);
+ putc('\n', hfile);
+ fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
+ fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
+ fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+ fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
+ putc('\n', hfile);
+ output_type_macros(); /* is_digit, etc. */
+ putc('\n', hfile);
+
+ /* Generate the syntax tables. */
+ fputs("#include \"shell.h\"\n", cfile);
+ fputs("#include \"syntax.h\"\n\n", cfile);
+ init();
+ fputs("/* syntax table used when not in quotes */\n", cfile);
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("'", "CSQUOTE");
+ add("\"", "CDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("<>();&| \t", "CSPCL");
+ syntax[1] = "CSPCL";
+ print("basesyntax");
+ init();
+ fputs("\n/* syntax table used when in double quotes */\n", cfile);
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("\"", "CENDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+ add("!*?[=~:/-]", "CCTL");
+ print("dqsyntax");
+ init();
+ fputs("\n/* syntax table used when in single quotes */\n", cfile);
+ add("\n", "CNL");
+ add("'", "CENDQUOTE");
+ /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+ add("!*?[=~:/-]\\", "CCTL");
+ print("sqsyntax");
+ init();
+ fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("(", "CLP");
+ add(")", "CRP");
+ print("arisyntax");
+ filltable("0");
+ fputs("\n/* character classification table */\n", cfile);
+ add("0123456789", "ISDIGIT");
+ add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
+ add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
+ add("_", "ISUNDER");
+ add("#?$!-*@", "ISSPECL");
+ print("is_type");
+ exit(0);
+ /* NOTREACHED */
+}
+
+
+
+/*
+ * Clear the syntax table.
+ */
+
+static void
+filltable(char *dftval)
+{
+ int i;
+
+ for (i = 0 ; i < 258; i++)
+ syntax[i] = dftval;
+}
+
+
+/*
+ * Initialize the syntax table with default values.
+ */
+
+static void
+init(void)
+{
+ int ctl;
+
+ filltable("CWORD");
+ syntax[0] = "CEOF";
+ syntax[1] = "CIGN";
+ for (ctl = CTL_FIRST; ctl <= CTL_LAST; ctl++ )
+ syntax[130 + ctl] = "CCTL";
+}
+
+
+/*
+ * Add entries to the syntax table.
+ */
+
+static void
+add(char *p, char *type)
+{
+ while (*p)
+ syntax[(signed char)*p++ + 130] = type;
+}
+
+
+
+/*
+ * Output the syntax table.
+ */
+
+static void
+print(char *name)
+{
+ int i;
+ int col;
+
+ fprintf(hfile, "extern const char %s[];\n", name);
+ fprintf(cfile, "const char %s[] = {\n", name);
+ col = 0;
+ for (i = 0 ; i < 258; i++) {
+ if (i == 0) {
+ fputs(" ", cfile);
+ } else if ((i & 03) == 0) {
+ fputs(",\n ", cfile);
+ col = 0;
+ } else {
+ putc(',', cfile);
+ while (++col < 9 * (i & 03))
+ putc(' ', cfile);
+ }
+ fputs(syntax[i], cfile);
+ col += strlen(syntax[i]);
+ }
+ fputs("\n};\n", cfile);
+}
+
+
+
+/*
+ * Output character classification macros (e.g. is_digit). If digits are
+ * contiguous, we can test for them quickly.
+ */
+
+static char *macro[] = {
+ "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)\n",
+ "#define is_alpha(c)\tisalpha((unsigned char)(c))\n",
+ "#define is_name(c)\t((c) == '_' || isalpha((unsigned char)(c)))\n",
+ "#define is_in_name(c)\t((c) == '_' || isalnum((unsigned char)(c)))\n",
+ "#define is_special(c)\t((is_type+SYNBASE)[(signed char)(c)] & (ISSPECL|ISDIGIT))\n",
+ NULL
+};
+
+static void
+output_type_macros(void)
+{
+ char **pp;
+
+ for (pp = macro ; *pp ; pp++)
+ fputs(*pp, hfile);
+ fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
+}
diff --git a/usr/dash/mktokens b/usr/dash/mktokens
new file mode 100644
index 0000000..8fbcef1
--- /dev/null
+++ b/usr/dash/mktokens
@@ -0,0 +1,92 @@
+#!/bin/sh -
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mktokens 8.1 (Berkeley) 5/31/93
+
+# The following is a list of tokens. The second column is nonzero if the
+# token marks the end of a list. The third column is the name to print in
+# error messages.
+
+cat > /tmp/ka$$ <<\!
+TEOF 1 end of file
+TNL 0 newline
+TSEMI 0 ";"
+TBACKGND 0 "&"
+TAND 0 "&&"
+TOR 0 "||"
+TPIPE 0 "|"
+TLP 0 "("
+TRP 1 ")"
+TENDCASE 1 ";;"
+TENDBQUOTE 1 "`"
+TREDIR 0 redirection
+TWORD 0 word
+TNOT 0 "!"
+TCASE 0 "case"
+TDO 1 "do"
+TDONE 1 "done"
+TELIF 1 "elif"
+TELSE 1 "else"
+TESAC 1 "esac"
+TFI 1 "fi"
+TFOR 0 "for"
+TIF 0 "if"
+TIN 0 "in"
+TTHEN 1 "then"
+TUNTIL 0 "until"
+TWHILE 0 "while"
+TBEGIN 0 "{"
+TEND 1 "}"
+!
+nl=`wc -l /tmp/ka$$`
+
+awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
+echo '
+/* Array indicating which tokens mark the end of a list */
+const char tokendlist[] = {'
+awk '{print "\t" $2 ","}' /tmp/ka$$
+echo '};
+
+const char *const tokname[] = {'
+sed -e 's/"/\\"/g' \
+ -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
+ /tmp/ka$$
+echo '};
+'
+sed 's/"//g' /tmp/ka$$ | awk '
+/TNOT/{print "#define KWDOFFSET " NR-1; print "";
+ print "STATIC const char *const parsekwd[] = {"}
+/TNOT/,/neverfound/{if (last) print " \"" last "\","; last = $3}
+END{print " \"" last "\"\n};"}'
+
+rm /tmp/ka$$
diff --git a/usr/dash/myhistedit.h b/usr/dash/myhistedit.h
new file mode 100644
index 0000000..5888088
--- /dev/null
+++ b/usr/dash/myhistedit.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+void setterm(const char *);
+int histcmd(int, char **);
+int not_fcnumber(char *);
+int str_to_event(const char *, int);
diff --git a/usr/dash/mystring.c b/usr/dash/mystring.c
new file mode 100644
index 0000000..0106bd2
--- /dev/null
+++ b/usr/dash/mystring.c
@@ -0,0 +1,257 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 functions.
+ *
+ * equal(s1, s2) Return true if strings are equal.
+ * scopy(from, to) Copy a string.
+ * scopyn(from, to, n) Like scopy, but checks for overflow.
+ * number(s) Convert a string of digits to an integer.
+ * is_number(s) Return true if s is a string of digits.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include "shell.h"
+#include "syntax.h"
+#include "error.h"
+#include "mystring.h"
+#include "memalloc.h"
+#include "parser.h"
+#include "system.h"
+
+
+char nullstr[1]; /* zero length string */
+const char spcstr[] = " ";
+const char snlfmt[] = "%s\n";
+const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=',
+ CTLQUOTEMARK, '\0' };
+const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
+const char illnum[] = "Illegal number: %s";
+const char homestr[] = "HOME";
+
+/*
+ * equal - #defined in mystring.h
+ */
+
+/*
+ * scopy - #defined in mystring.h
+ */
+
+
+#if 0
+/*
+ * scopyn - copy a string from "from" to "to", truncating the string
+ * if necessary. "To" is always nul terminated, even if
+ * truncation is performed. "Size" is the size of "to".
+ */
+
+void
+scopyn(const char *from, char *to, int size)
+{
+
+ while (--size > 0) {
+ if ((*to++ = *from++) == '\0')
+ return;
+ }
+ *to = '\0';
+}
+#endif
+
+
+/*
+ * prefix -- see if pfx is a prefix of string.
+ */
+
+char *
+prefix(const char *string, const char *pfx)
+{
+ while (*pfx) {
+ if (*pfx++ != *string++)
+ return 0;
+ }
+ return (char *) string;
+}
+
+void badnum(const char *s)
+{
+ sh_error(illnum, s);
+}
+
+/*
+ * Convert a string into an integer of type intmax_t. Alow trailing spaces.
+ */
+intmax_t atomax(const char *s, int base)
+{
+ char *p;
+ intmax_t r;
+
+ errno = 0;
+ r = strtoimax(s, &p, base);
+
+ if (errno != 0)
+ badnum(s);
+
+ /*
+ * Disallow completely blank strings in non-arithmetic (base != 0)
+ * contexts.
+ */
+ if (p == s && base)
+ badnum(s);
+
+ while (isspace((unsigned char)*p))
+ p++;
+
+ if (*p)
+ badnum(s);
+
+ return r;
+}
+
+intmax_t atomax10(const char *s)
+{
+ return atomax(s, 10);
+}
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+ intmax_t n = atomax10(s);
+
+ if (n < 0 || n > INT_MAX)
+ badnum(s);
+
+ return n;
+}
+
+
+
+/*
+ * Check for a valid number. This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+ do {
+ if (! is_digit(*p))
+ return 0;
+ } while (*++p != '\0');
+ return 1;
+}
+
+
+/*
+ * Produce a possibly single quoted string suitable as input to the shell.
+ * The return string is allocated on the stack.
+ */
+
+char *
+single_quote(const char *s) {
+ char *p;
+
+ STARTSTACKSTR(p);
+
+ do {
+ char *q;
+ size_t len;
+
+ len = strchrnul(s, '\'') - s;
+
+ q = p = makestrspace(len + 3, p);
+
+ *q++ = '\'';
+ q = mempcpy(q, s, len);
+ *q++ = '\'';
+ s += len;
+
+ STADJUST(q - p, p);
+
+ len = strspn(s, "'");
+ if (!len)
+ break;
+
+ q = p = makestrspace(len + 3, p);
+
+ *q++ = '"';
+ q = mempcpy(q, s, len);
+ *q++ = '"';
+ s += len;
+
+ STADJUST(q - p, p);
+ } while (*s);
+
+ USTPUTC(0, p);
+
+ return stackblock();
+}
+
+/*
+ * Like strdup but works with the ash stack.
+ */
+
+char *
+sstrdup(const char *p)
+{
+ size_t len = strlen(p) + 1;
+ return memcpy(stalloc(len), p, len);
+}
+
+/*
+ * Wrapper around strcmp for qsort/bsearch/...
+ */
+int
+pstrcmp(const void *a, const void *b)
+{
+ return strcmp(*(const char *const *) a, *(const char *const *) b);
+}
+
+/*
+ * Find a string is in a sorted array.
+ */
+const char *const *
+findstring(const char *s, const char *const *array, size_t nmemb)
+{
+ return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
+}
diff --git a/usr/dash/mystring.h b/usr/dash/mystring.h
new file mode 100644
index 0000000..083ea98
--- /dev/null
+++ b/usr/dash/mystring.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mystring.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+#include <string.h>
+
+extern const char snlfmt[];
+extern const char spcstr[];
+extern const char dolatstr[];
+#define DOLATSTRLEN 6
+extern const char qchars[];
+extern const char illnum[];
+extern const char homestr[];
+
+#if 0
+void scopyn(const char *, char *, int);
+#endif
+char *prefix(const char *, const char *);
+void badnum(const char *s) __attribute__ ((noreturn));
+intmax_t atomax(const char *, int);
+intmax_t atomax10(const char *);
+int number(const char *);
+int is_number(const char *);
+char *single_quote(const char *);
+char *sstrdup(const char *);
+int pstrcmp(const void *, const void *);
+const char *const *findstring(const char *, const char *const *, size_t);
+
+#define equal(s1, s2) (strcmp(s1, s2) == 0)
+#define scopy(s1, s2) ((void)strcpy(s2, s1))
diff --git a/usr/dash/nodes.c.pat b/usr/dash/nodes.c.pat
new file mode 100644
index 0000000..9125bc7
--- /dev/null
+++ b/usr/dash/nodes.c.pat
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
+ */
+
+#include <stdlib.h>
+/*
+ * Routine for dealing with parsed shell commands.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "memalloc.h"
+#include "machdep.h"
+#include "mystring.h"
+#include "system.h"
+
+
+int funcblocksize; /* size of structures in function */
+int funcstringsize; /* size of strings in node */
+pointer funcblock; /* block to allocate function from */
+char *funcstring; /* block to allocate strings from */
+
+%SIZES
+
+
+STATIC void calcsize(union node *);
+STATIC void sizenodelist(struct nodelist *);
+STATIC union node *copynode(union node *);
+STATIC struct nodelist *copynodelist(struct nodelist *);
+STATIC char *nodesavestr(char *);
+
+
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+struct funcnode *
+copyfunc(union node *n)
+{
+ struct funcnode *f;
+ size_t blocksize;
+
+ funcblocksize = offsetof(struct funcnode, n);
+ funcstringsize = 0;
+ calcsize(n);
+ blocksize = funcblocksize;
+ f = ckmalloc(blocksize + funcstringsize);
+ funcblock = (char *) f + offsetof(struct funcnode, n);
+ funcstring = (char *) f + blocksize;
+ copynode(n);
+ f->count = 0;
+ return f;
+}
+
+
+
+STATIC void
+calcsize(n)
+ union node *n;
+{
+ %CALCSIZE
+}
+
+
+
+STATIC void
+sizenodelist(lp)
+ struct nodelist *lp;
+{
+ while (lp) {
+ funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
+ calcsize(lp->n);
+ lp = lp->next;
+ }
+}
+
+
+
+STATIC union node *
+copynode(n)
+ union node *n;
+{
+ union node *new;
+
+ %COPY
+ return new;
+}
+
+
+STATIC struct nodelist *
+copynodelist(lp)
+ struct nodelist *lp;
+{
+ struct nodelist *start;
+ struct nodelist **lpp;
+
+ lpp = &start;
+ while (lp) {
+ *lpp = funcblock;
+ funcblock = (char *) funcblock +
+ SHELL_ALIGN(sizeof(struct nodelist));
+ (*lpp)->n = copynode(lp->n);
+ lp = lp->next;
+ lpp = &(*lpp)->next;
+ }
+ *lpp = NULL;
+ return start;
+}
+
+
+
+STATIC char *
+nodesavestr(s)
+ char *s;
+{
+ char *rtn = funcstring;
+
+ funcstring = stpcpy(funcstring, s) + 1;
+ return rtn;
+}
+
+
+
+/*
+ * Free a parse tree.
+ */
+
+void
+freefunc(struct funcnode *f)
+{
+ if (f && --f->count < 0)
+ ckfree(f);
+}
diff --git a/usr/dash/nodetypes b/usr/dash/nodetypes
new file mode 100644
index 0000000..ceaf478
--- /dev/null
+++ b/usr/dash/nodetypes
@@ -0,0 +1,151 @@
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+# Copyright (c) 1997-2005
+# Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)nodetypes 8.2 (Berkeley) 5/4/95
+
+# This file describes the nodes used in parse trees. Unindented lines
+# contain a node type followed by a structure tag. Subsequent indented
+# lines specify the fields of the structure. Several node types can share
+# the same structure, in which case the fields of the structure should be
+# specified only once.
+#
+# A field of a structure is described by the name of the field followed
+# by a type. The currently implemented types are:
+# nodeptr - a pointer to a node
+# nodelist - a pointer to a list of nodes
+# string - a pointer to a nul terminated string
+# int - an integer
+# other - any type that can be copied by assignment
+# temp - a field that doesn't have to be copied when the node is copied
+# The last two types should be followed by the text of a C declaration for
+# the field.
+
+NCMD ncmd # a simple command
+ type int
+ linno int
+ assign nodeptr # variable assignments
+ args nodeptr # the arguments
+ redirect nodeptr # list of file redirections
+
+NPIPE npipe # a pipeline
+ type int
+ backgnd int # set to run pipeline in background
+ cmdlist nodelist # the commands in the pipeline
+
+NREDIR nredir # redirection (of a complex command)
+ type int
+ linno int
+ n nodeptr # the command
+ redirect nodeptr # list of file redirections
+
+NBACKGND nredir # run command in background
+NSUBSHELL nredir # run command in a subshell
+
+NAND nbinary # the && operator
+NOR nbinary # the || operator
+
+NSEMI nbinary # two commands separated by a semicolon
+ type int
+ ch1 nodeptr # the first child
+ ch2 nodeptr # the second child
+
+NIF nif # the if statement. Elif clauses are handled
+ type int # using multiple if nodes.
+ test nodeptr # if test
+ ifpart nodeptr # then ifpart
+ elsepart nodeptr # else elsepart
+
+NWHILE nbinary # the while statement. First child is the test
+NUNTIL nbinary # the until statement
+
+NFOR nfor # the for statement
+ type int
+ linno int
+ args nodeptr # for var in args
+ body nodeptr # do body; done
+ var string # the for variable
+
+NCASE ncase # a case statement
+ type int
+ linno int
+ expr nodeptr # the word to switch on
+ cases nodeptr # the list of cases (NCLIST nodes)
+
+NCLIST nclist # a case
+ type int
+ next nodeptr # the next case in list
+ pattern nodeptr # list of patterns for this case
+ body nodeptr # code to execute for this case
+
+
+NDEFUN ndefun # a function
+ type int
+ linno int
+ text string
+ body nodeptr
+
+NARG narg # represents a word
+ type int
+ next nodeptr # next word in list
+ text string # the text of the word
+ backquote nodelist # list of commands in back quotes
+
+NTO nfile # fd> fname
+NCLOBBER nfile # fd>| fname
+NFROM nfile # fd< fname
+NFROMTO nfile # fd<> fname
+NAPPEND nfile # fd>> fname
+ type int
+ next nodeptr # next redirection in list
+ fd int # file descriptor being redirected
+ fname nodeptr # file name, in a NARG node
+ expfname temp char *expfname # actual file name
+
+NTOFD ndup # fd<&dupfd
+NFROMFD ndup # fd>&dupfd
+ type int
+ next nodeptr # next redirection in list
+ fd int # file descriptor being redirected
+ dupfd int # file descriptor to duplicate
+ vname nodeptr # file name if fd>&$var
+
+
+NHERE nhere # fd<<\!
+NXHERE nhere # fd<<!
+ type int
+ next nodeptr # next redirection in list
+ fd int # file descriptor being redirected
+ doc nodeptr # input to command (NARG node)
+
+NNOT nnot # ! command (actually pipeline)
+ type int
+ com nodeptr
diff --git a/usr/dash/options.c b/usr/dash/options.c
new file mode 100644
index 0000000..6f381e6
--- /dev/null
+++ b/usr/dash/options.c
@@ -0,0 +1,559 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#define DEFINE_OPTIONS
+#include "options.h"
+#undef DEFINE_OPTIONS
+#include "nodes.h" /* for other header files */
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "show.h"
+
+char *arg0; /* value of $0 */
+struct shparam shellparam; /* current positional parameters */
+char **argptr; /* argument list for builtin commands */
+char *optionarg; /* set by nextopt (like getopt) */
+char *optptr; /* used by nextopt */
+
+char *minusc; /* argument to -c option */
+
+static const char *const optnames[NOPTS] = {
+ "errexit",
+ "noglob",
+ "ignoreeof",
+ "interactive",
+ "monitor",
+ "noexec",
+ "stdin",
+ "xtrace",
+ "verbose",
+ "vi",
+ "emacs",
+ "noclobber",
+ "allexport",
+ "notify",
+ "nounset",
+ "nolog",
+ "debug",
+};
+
+const char optletters[NOPTS] = {
+ 'e',
+ 'f',
+ 'I',
+ 'i',
+ 'm',
+ 'n',
+ 's',
+ 'x',
+ 'v',
+ 'V',
+ 'E',
+ 'C',
+ 'a',
+ 'b',
+ 'u',
+ 0,
+ 0,
+};
+
+char optlist[NOPTS];
+
+
+static int options(int);
+STATIC void minus_o(char *, int);
+STATIC void setoption(int, int);
+STATIC int getopts(char *, char *, char **);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+int
+procargs(int argc, char **argv)
+{
+ int i;
+ const char *xminusc;
+ char **xargv;
+ int login;
+
+ xargv = argv;
+ login = xargv[0] && xargv[0][0] == '-';
+ arg0 = xargv[0];
+ if (argc > 0)
+ xargv++;
+ for (i = 0; i < NOPTS; i++)
+ optlist[i] = 2;
+ argptr = xargv;
+ login |= options(1);
+ xargv = argptr;
+ xminusc = minusc;
+ if (*xargv == NULL) {
+ if (xminusc)
+ sh_error("-c requires an argument");
+ sflag = 1;
+ }
+ if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
+ iflag = 1;
+ if (mflag == 2)
+ mflag = iflag;
+ for (i = 0; i < NOPTS; i++)
+ if (optlist[i] == 2)
+ optlist[i] = 0;
+#if DEBUG == 2
+ debug = 1;
+#endif
+ /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+ if (xminusc) {
+ minusc = *xargv++;
+ if (*xargv)
+ goto setarg0;
+ } else if (!sflag) {
+ setinputfile(*xargv, 0);
+setarg0:
+ arg0 = *xargv++;
+ commandname = arg0;
+ }
+
+ shellparam.p = xargv;
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+ /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+ while (*xargv) {
+ shellparam.nparam++;
+ xargv++;
+ }
+ optschanged();
+
+ return login;
+}
+
+
+void
+optschanged(void)
+{
+#ifdef DEBUG
+ opentrace();
+#endif
+ setinteractive(iflag);
+#ifndef SMALL
+ histedit();
+#endif
+ setjobctl(mflag);
+}
+
+/*
+ * Process shell options. The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ */
+
+STATIC int
+options(int cmdline)
+{
+ char *p;
+ int val;
+ int c;
+ int login = 0;
+
+ if (cmdline)
+ minusc = NULL;
+ while ((p = *argptr) != NULL) {
+ argptr++;
+ if ((c = *p++) == '-') {
+ val = 1;
+ if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+ if (!cmdline) {
+ /* "-" means turn off -x and -v */
+ if (p[0] == '\0')
+ xflag = vflag = 0;
+ /* "--" means reset params */
+ else if (*argptr == NULL)
+ setparam(argptr);
+ }
+ break; /* "-" or "--" terminates options */
+ }
+ } else if (c == '+') {
+ val = 0;
+ } else {
+ argptr--;
+ break;
+ }
+ while ((c = *p++) != '\0') {
+ if (c == 'c' && cmdline) {
+ minusc = p; /* command is after shell args*/
+ } else if (c == 'l' && cmdline) {
+ login = 1;
+ } else if (c == 'o') {
+ minus_o(*argptr, val);
+ if (*argptr)
+ argptr++;
+ } else {
+ setoption(c, val);
+ }
+ }
+ }
+
+ return login;
+}
+
+STATIC void
+minus_o(char *name, int val)
+{
+ int i;
+
+ if (name == NULL) {
+ if (val) {
+ out1str("Current option settings\n");
+ for (i = 0; i < NOPTS; i++)
+ out1fmt("%-16s%s\n", optnames[i],
+ optlist[i] ? "on" : "off");
+ } else {
+ for (i = 0; i < NOPTS; i++)
+ out1fmt("set %s %s\n",
+ optlist[i] ? "-o" : "+o",
+ optnames[i]);
+
+ }
+ } else {
+ for (i = 0; i < NOPTS; i++)
+ if (equal(name, optnames[i])) {
+ optlist[i] = val;
+ return;
+ }
+ sh_error("Illegal option -o %s", name);
+ }
+}
+
+
+STATIC void
+setoption(int flag, int val)
+{
+ int i;
+
+ for (i = 0; i < NOPTS; i++)
+ if (optletters[i] == flag) {
+ optlist[i] = val;
+ if (val) {
+ /* #%$ hack for ksh semantics */
+ if (flag == 'V')
+ Eflag = 0;
+ else if (flag == 'E')
+ Vflag = 0;
+ }
+ return;
+ }
+ sh_error("Illegal option -%c", flag);
+ /* NOTREACHED */
+}
+
+
+
+/*
+ * Set the shell parameters.
+ */
+
+void
+setparam(char **argv)
+{
+ char **newparam;
+ char **ap;
+ int nparam;
+
+ for (nparam = 0 ; argv[nparam] ; nparam++);
+ ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
+ while (*argv) {
+ *ap++ = savestr(*argv++);
+ }
+ *ap = NULL;
+ freeparam(&shellparam);
+ shellparam.malloc = 1;
+ shellparam.nparam = nparam;
+ shellparam.p = newparam;
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(volatile struct shparam *param)
+{
+ char **ap;
+
+ if (param->malloc) {
+ for (ap = param->p ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->p);
+ }
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+ int n;
+ char **ap1, **ap2;
+
+ n = 1;
+ if (argc > 1)
+ n = number(argv[1]);
+ if (n > shellparam.nparam)
+ sh_error("can't shift that many");
+ INTOFF;
+ shellparam.nparam -= n;
+ for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
+ if (shellparam.malloc)
+ ckfree(*ap1);
+ }
+ ap2 = shellparam.p;
+ while ((*ap2++ = *ap1++) != NULL);
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+ INTON;
+ return 0;
+}
+
+
+
+/*
+ * The set command builtin.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+ if (argc == 1)
+ return showvars(nullstr, 0, VUNSET);
+ INTOFF;
+ options(0);
+ optschanged();
+ if (*argptr != NULL) {
+ setparam(argptr);
+ }
+ INTON;
+ return 0;
+}
+
+
+void
+getoptsreset(value)
+ const char *value;
+{
+ shellparam.optind = number(value) ?: 1;
+ shellparam.optoff = -1;
+}
+
+/*
+ * The getopts builtin. Shellparam.optnext points to the next argument
+ * to be processed. Shellparam.optptr points to the next character to
+ * be processed in the current argument. If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+ char **optbase;
+
+ if (argc < 3)
+ sh_error("Usage: getopts optstring var [arg]");
+ else if (argc == 3) {
+ optbase = shellparam.p;
+ if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+ }
+ }
+ else {
+ optbase = &argv[3];
+ if ((unsigned)shellparam.optind > argc - 2) {
+ shellparam.optind = 1;
+ shellparam.optoff = -1;
+ }
+ }
+
+ return getopts(argv[1], argv[2], optbase);
+}
+
+STATIC int
+getopts(char *optstr, char *optvar, char **optfirst)
+{
+ char *p, *q;
+ char c = '?';
+ int done = 0;
+ char s[2];
+ char **optnext;
+ int ind = shellparam.optind;
+ int off = shellparam.optoff;
+
+ shellparam.optind = -1;
+ optnext = optfirst + ind - 1;
+
+ if (ind <= 1 || off < 0 || strlen(optnext[-1]) < off)
+ p = NULL;
+ else
+ p = optnext[-1] + off;
+ if (p == NULL || *p == '\0') {
+ /* Current word is done, advance */
+ p = *optnext;
+ if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+ p = NULL;
+ done = 1;
+ goto out;
+ }
+ optnext++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ goto atend;
+ }
+
+ c = *p++;
+ for (q = optstr; *q != c; ) {
+ if (*q == '\0') {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ setvar("OPTARG", s, 0);
+ } else {
+ outfmt(&errout, "Illegal option -%c\n", c);
+ (void) unsetvar("OPTARG");
+ }
+ c = '?';
+ goto out;
+ }
+ if (*++q == ':')
+ q++;
+ }
+
+ if (*++q == ':') {
+ if (*p == '\0' && (p = *optnext) == NULL) {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ setvar("OPTARG", s, 0);
+ c = ':';
+ } else {
+ outfmt(&errout, "No arg for -%c option\n", c);
+ (void) unsetvar("OPTARG");
+ c = '?';
+ }
+ goto out;
+ }
+
+ if (p == *optnext)
+ optnext++;
+ setvar("OPTARG", p, 0);
+ p = NULL;
+ } else
+ setvar("OPTARG", nullstr, 0);
+
+out:
+ ind = optnext - optfirst + 1;
+ setvarint("OPTIND", ind, VNOFUNC);
+ s[0] = c;
+ s[1] = '\0';
+ setvar(optvar, s, 0);
+
+ shellparam.optoff = p ? p - *(optnext - 1) : -1;
+ shellparam.optind = ind;
+
+ return done;
+}
+
+/*
+ * XXX - should get rid of. have all builtins use getopt(3). the
+ * library getopt must have the BSD extension static variable "optreset"
+ * otherwise it can't be used within the shell safely.
+ *
+ * Standard option processing (a la getopt) for builtin routines. The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary. It return the character, or '\0' on
+ * end of input.
+ */
+
+int
+nextopt(const char *optstring)
+{
+ char *p;
+ const char *q;
+ char c;
+
+ if ((p = optptr) == NULL || *p == '\0') {
+ p = *argptr;
+ if (p == NULL || *p != '-' || *++p == '\0')
+ return '\0';
+ argptr++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ return '\0';
+ }
+ c = *p++;
+ for (q = optstring ; *q != c ; ) {
+ if (*q == '\0')
+ sh_error("Illegal option -%c", c);
+ if (*++q == ':')
+ q++;
+ }
+ if (*++q == ':') {
+ if (*p == '\0' && (p = *argptr++) == NULL)
+ sh_error("No arg for -%c option", c);
+ optionarg = p;
+ p = NULL;
+ }
+ optptr = p;
+ return c;
+}
diff --git a/usr/dash/options.h b/usr/dash/options.h
new file mode 100644
index 0000000..975fe33
--- /dev/null
+++ b/usr/dash/options.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)options.h 8.2 (Berkeley) 5/4/95
+ */
+
+struct shparam {
+ int nparam; /* # of positional parameters (without $0) */
+ unsigned char malloc; /* if parameter list dynamically allocated */
+ char **p; /* parameter list */
+ int optind; /* next parameter to be processed by getopts */
+ int optoff; /* used by getopts */
+};
+
+
+
+#define eflag optlist[0]
+#define fflag optlist[1]
+#define Iflag optlist[2]
+#define iflag optlist[3]
+#define mflag optlist[4]
+#define nflag optlist[5]
+#define sflag optlist[6]
+#define xflag optlist[7]
+#define vflag optlist[8]
+#define Vflag optlist[9]
+#define Eflag optlist[10]
+#define Cflag optlist[11]
+#define aflag optlist[12]
+#define bflag optlist[13]
+#define uflag optlist[14]
+#define nolog optlist[15]
+#define debug optlist[16]
+
+#define NOPTS 17
+
+extern const char optletters[NOPTS];
+extern char optlist[NOPTS];
+
+
+extern char *minusc; /* argument to -c option */
+extern char *arg0; /* $0 */
+extern struct shparam shellparam; /* $@ */
+extern char **argptr; /* argument list for builtin commands */
+extern char *optionarg; /* set by nextopt */
+extern char *optptr; /* used by nextopt */
+
+int procargs(int, char **);
+void optschanged(void);
+void setparam(char **);
+void freeparam(volatile struct shparam *);
+int shiftcmd(int, char **);
+int setcmd(int, char **);
+int getoptscmd(int, char **);
+int nextopt(const char *);
+void getoptsreset(const char *);
diff --git a/usr/dash/output.c b/usr/dash/output.c
new file mode 100644
index 0000000..bb7c6ad
--- /dev/null
+++ b/usr/dash/output.c
@@ -0,0 +1,399 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 output routines. We use our own output routines because:
+ * When a builtin command is interrupted we have to discard
+ * any pending output.
+ * When a builtin command appears in back quotes, we want to
+ * save the output of the command in a region obtained
+ * via malloc, rather than doing a fork and reading the
+ * output of the command via a pipe.
+ * Our output routines may be smaller than the stdio routines.
+ */
+
+#include <sys/types.h> /* quad_t */
+#include <sys/param.h> /* BSD4_4 */
+#include <sys/ioctl.h>
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef USE_GLIBC_STDIO
+#include <fcntl.h>
+#endif
+#include <limits.h>
+
+#include "shell.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "main.h"
+#include "system.h"
+
+
+#define OUTBUFSIZ BUFSIZ
+#define MEM_OUT -3 /* output to dynamically allocated memory */
+
+
+#ifdef USE_GLIBC_STDIO
+struct output output = {
+ .stream = 0, .nextc = 0, .end = 0, .buf = 0, .bufsize = 0, .fd = 1, .flags = 0
+};
+struct output errout = {
+ .stream = 0, .nextc = 0, .end = 0, .buf = 0, .bufsize = 0, .fd = 2, .flags = 0
+}
+#ifdef notyet
+struct output memout = {
+ .stream = 0, .nextc = 0, .end = 0, .buf = 0, .bufsize = 0, .fd = MEM_OUT, .flags = 0
+};
+#endif
+#else
+struct output output = {
+ .nextc = 0, .end = 0, .buf = 0, .bufsize = OUTBUFSIZ, .fd = 1, .flags = 0
+};
+struct output errout = {
+ .nextc = 0, .end = 0, .buf = 0, .bufsize = 0, .fd = 2, .flags = 0
+};
+struct output preverrout;
+#ifdef notyet
+struct output memout = {
+ .nextc = 0, .end = 0, .buf = 0, .bufsize = 0, .fd = MEM_OUT, .flags = 0
+};
+#endif
+#endif
+struct output *out1 = &output;
+struct output *out2 = &errout;
+
+
+#ifndef USE_GLIBC_STDIO
+static void __outstr(const char *, size_t, struct output *);
+#endif
+static int xvsnprintf(char *, size_t, const char *, va_list);
+
+
+#ifdef mkinit
+
+INCLUDE "output.h"
+INCLUDE "memalloc.h"
+
+INIT {
+#ifdef USE_GLIBC_STDIO
+ initstreams();
+#endif
+}
+
+RESET {
+#ifdef notyet
+ out1 = &output;
+ out2 = &errout;
+#ifdef USE_GLIBC_STDIO
+ if (memout.stream != NULL)
+ __closememout();
+#endif
+ if (memout.buf != NULL) {
+ ckfree(memout.buf);
+ memout.buf = NULL;
+ }
+#endif
+}
+
+#endif
+
+
+#ifndef USE_GLIBC_STDIO
+static void
+__outstr(const char *p, size_t len, struct output *dest)
+{
+ size_t bufsize;
+ size_t offset;
+ size_t nleft;
+
+ nleft = dest->end - dest->nextc;
+ if (nleft >= len) {
+buffered:
+ dest->nextc = mempcpy(dest->nextc, p, len);
+ return;
+ }
+
+ bufsize = dest->bufsize;
+ if (!bufsize) {
+ ;
+ } else if (dest->buf == NULL) {
+ if (dest->fd == MEM_OUT && len > bufsize) {
+ bufsize = len;
+ }
+ offset = 0;
+ goto alloc;
+ } else if (dest->fd == MEM_OUT) {
+ offset = bufsize;
+ if (bufsize >= len) {
+ bufsize <<= 1;
+ } else {
+ bufsize += len;
+ }
+ if (bufsize < offset)
+ goto err;
+alloc:
+ INTOFF;
+ dest->buf = ckrealloc(dest->buf, bufsize);
+ dest->bufsize = bufsize;
+ dest->end = dest->buf + bufsize;
+ dest->nextc = dest->buf + offset;
+ INTON;
+ } else {
+ flushout(dest);
+ }
+
+ nleft = dest->end - dest->nextc;
+ if (nleft > len)
+ goto buffered;
+
+ if ((xwrite(dest->fd, p, len))) {
+err:
+ dest->flags |= OUTPUT_ERR;
+ }
+}
+#endif
+
+
+void
+outstr(const char *p, struct output *file)
+{
+#ifdef USE_GLIBC_STDIO
+ INTOFF;
+ fputs(p, file->stream);
+ INTON;
+#else
+ size_t len;
+
+ len = strlen(p);
+ __outstr(p, len, file);
+#endif
+}
+
+
+#ifndef USE_GLIBC_STDIO
+
+
+void
+outcslow(int c, struct output *dest)
+{
+ char buf = c;
+ __outstr(&buf, 1, dest);
+}
+#endif
+
+
+void
+flushall(void)
+{
+ flushout(&output);
+#ifdef FLUSHERR
+ flushout(&errout);
+#endif
+}
+
+
+void
+flushout(struct output *dest)
+{
+#ifdef USE_GLIBC_STDIO
+ INTOFF;
+ fflush(dest->stream);
+ INTON;
+#else
+ size_t len;
+
+ len = dest->nextc - dest->buf;
+ if (!len || dest->fd < 0)
+ return;
+ dest->nextc = dest->buf;
+ if ((xwrite(dest->fd, dest->buf, len)))
+ dest->flags |= OUTPUT_ERR;
+#endif
+}
+
+
+void
+outfmt(struct output *file, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(file, fmt, ap);
+ va_end(ap);
+}
+
+
+void
+out1fmt(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(out1, fmt, ap);
+ va_end(ap);
+}
+
+
+int
+fmtstr(char *outbuf, size_t length, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = xvsnprintf(outbuf, length, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+
+#ifndef USE_GLIBC_STDIO
+void
+doformat(struct output *dest, const char *f, va_list ap)
+{
+ struct stackmark smark;
+ char *s;
+ int len, ret;
+ size_t size;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ size = dest->end - dest->nextc;
+ len = xvsnprintf(dest->nextc, size, f, ap2);
+ va_end(ap2);
+ if (len < 0) {
+ dest->flags |= OUTPUT_ERR;
+ return;
+ }
+ if (len < size) {
+ dest->nextc += len;
+ return;
+ }
+ setstackmark(&smark);
+ s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+ ret = xvsnprintf(s, len + 1, f, ap);
+ if (ret == len)
+ __outstr(s, len, dest);
+ else
+ dest->flags |= OUTPUT_ERR;
+ popstackmark(&smark);
+}
+#endif
+
+
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+int
+xwrite(int fd, const void *p, size_t n)
+{
+ const char *buf = p;
+
+ while (n) {
+ ssize_t i;
+ size_t m;
+
+ m = n;
+ if (m > SSIZE_MAX)
+ m = SSIZE_MAX;
+ do {
+ i = write(fd, buf, m);
+ } while (i < 0 && errno == EINTR);
+ if (i < 0)
+ return -1;
+ buf += i;
+ n -= i;
+ }
+ return 0;
+}
+
+
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams() {
+ output.stream = stdout;
+ errout.stream = stderr;
+}
+
+
+void
+openmemout(void) {
+ INTOFF;
+ memout.stream = open_memstream(&memout.buf, &memout.bufsize);
+ INTON;
+}
+
+
+int
+__closememout(void) {
+ int error;
+ error = fclose(memout.stream);
+ memout.stream = NULL;
+ return error;
+}
+#endif
+#endif
+
+
+static int
+xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap)
+{
+ int ret;
+
+#ifdef __sun
+ /*
+ * vsnprintf() on older versions of Solaris returns -1 when
+ * passed a length of 0. To avoid this, use a dummy
+ * 1-character buffer instead.
+ */
+ char dummy[1];
+
+ if (length == 0) {
+ outbuf = dummy;
+ length = sizeof(dummy);
+ }
+#endif
+
+ INTOFF;
+ ret = vsnprintf(outbuf, length, fmt, ap);
+ INTON;
+ return ret;
+}
diff --git a/usr/dash/output.h b/usr/dash/output.h
new file mode 100644
index 0000000..f853e9d
--- /dev/null
+++ b/usr/dash/output.h
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)output.h 8.2 (Berkeley) 5/4/95
+ */
+
+#ifndef OUTPUT_INCL
+
+#include <stdarg.h>
+#ifdef USE_GLIBC_STDIO
+#include <stdio.h>
+#endif
+#include <sys/types.h>
+
+struct output {
+#ifdef USE_GLIBC_STDIO
+ FILE *stream;
+#endif
+ char *nextc;
+ char *end;
+ char *buf;
+ size_t bufsize;
+ int fd;
+ int flags;
+};
+
+extern struct output output;
+extern struct output errout;
+extern struct output preverrout;
+#ifdef notyet
+extern struct output memout;
+#endif
+extern struct output *out1;
+extern struct output *out2;
+
+void outstr(const char *, struct output *);
+#ifndef USE_GLIBC_STDIO
+void outcslow(int, struct output *);
+#endif
+void flushall(void);
+void flushout(struct output *);
+void outfmt(struct output *, const char *, ...)
+ __attribute__((__format__(__printf__,2,3)));
+void out1fmt(const char *, ...)
+ __attribute__((__format__(__printf__,1,2)));
+int fmtstr(char *, size_t, const char *, ...)
+ __attribute__((__format__(__printf__,3,4)));
+#ifndef USE_GLIBC_STDIO
+void doformat(struct output *, const char *, va_list);
+#endif
+int xwrite(int, const void *, size_t);
+#ifdef notyet
+#ifdef USE_GLIBC_STDIO
+void initstreams(void);
+void openmemout(void);
+int __closememout(void);
+#endif
+#endif
+
+static inline void
+freestdout()
+{
+ output.nextc = output.buf;
+ output.flags = 0;
+}
+
+#define OUTPUT_ERR 01 /* error occurred on output */
+
+#ifdef USE_GLIBC_STDIO
+static inline void outc(int ch, struct output *file)
+{
+ putc(ch, file->stream);
+}
+#define doformat(d, f, a) vfprintf((d)->stream, (f), (a))
+#else
+static inline void outc(int ch, struct output *file)
+{
+ if (file->nextc == file->end)
+ outcslow(ch, file);
+ else {
+ *file->nextc = ch;
+ file->nextc++;
+ }
+}
+#endif
+#define out1c(c) outc((c), out1)
+#define out2c(c) outcslow((c), out2)
+#define out1str(s) outstr((s), out1)
+#define out2str(s) outstr((s), out2)
+#define outerr(f) (f)->flags
+
+#define OUTPUT_INCL
+#endif
diff --git a/usr/dash/parser.c b/usr/dash/parser.c
new file mode 100644
index 0000000..6e076a5
--- /dev/null
+++ b/usr/dash/parser.c
@@ -0,0 +1,1568 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <stdlib.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h" /* defines rmescapes() */
+#include "exec.h" /* defines find_builtin() */
+#include "syntax.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "var.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "show.h"
+#include "builtins.h"
+#include "system.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+
+/*
+ * Shell command parser.
+ */
+
+/* values returned by readtoken */
+#include "token.h"
+
+
+
+/* Used by expandstr to get here-doc like behaviour. */
+#define FAKEEOFMARK (char *)1
+
+
+
+struct heredoc {
+ struct heredoc *next; /* next here document in list */
+ union node *here; /* redirection node */
+ char *eofmark; /* string indicating end of input */
+ int striptabs; /* if set, strip leading tabs */
+};
+
+
+
+struct heredoc *heredoclist; /* list of here documents to read */
+int doprompt; /* if set, prompt the user */
+int needprompt; /* true if interactive and at start of line */
+int lasttoken; /* last token read */
+MKINIT int tokpushback; /* last token pushed back */
+char *wordtext; /* text of last word returned by readtoken */
+int checkkwd;
+struct nodelist *backquotelist;
+union node *redirnode;
+struct heredoc *heredoc;
+int quoteflag; /* set if (part of) last token was quoted */
+
+
+STATIC union node *list(int);
+STATIC union node *andor(void);
+STATIC union node *pipeline(void);
+STATIC union node *command(void);
+STATIC union node *simplecmd(void);
+STATIC union node *makename(void);
+STATIC void parsefname(void);
+STATIC void parseheredoc(void);
+STATIC int peektoken(void);
+STATIC int readtoken(void);
+STATIC int xxreadtoken(void);
+STATIC int readtoken1(int, char const *, char *, int);
+STATIC void synexpect(int) __attribute__((__noreturn__));
+STATIC void synerror(const char *) __attribute__((__noreturn__));
+STATIC void setprompt(int);
+
+
+static inline int
+isassignment(const char *p)
+{
+ const char *q = endofname(p);
+ if (p == q)
+ return 0;
+ return *q == '=';
+}
+
+static inline int realeofmark(const char *eofmark)
+{
+ return eofmark && eofmark != FAKEEOFMARK;
+}
+
+
+/*
+ * Read and parse a command. Returns NEOF on end of file. (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+ int t;
+
+ tokpushback = 0;
+ doprompt = interact;
+ if (doprompt)
+ setprompt(doprompt);
+ needprompt = 0;
+ t = readtoken();
+ if (t == TEOF)
+ return NEOF;
+ if (t == TNL)
+ return NULL;
+ tokpushback++;
+ return list(1);
+}
+
+
+STATIC union node *
+list(int nlflag)
+{
+ union node *n1, *n2, *n3;
+ int tok;
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (nlflag == 2 && tokendlist[peektoken()])
+ return NULL;
+ n1 = NULL;
+ for (;;) {
+ n2 = andor();
+ tok = readtoken();
+ if (tok == TBACKGND) {
+ if (n2->type == NPIPE) {
+ n2->npipe.backgnd = 1;
+ } else {
+ if (n2->type != NREDIR) {
+ n3 = stalloc(sizeof(struct nredir));
+ n3->nredir.n = n2;
+ n3->nredir.redirect = NULL;
+ n2 = n3;
+ }
+ n2->type = NBACKGND;
+ }
+ }
+ if (n1 == NULL) {
+ n1 = n2;
+ }
+ else {
+ n3 = (union node *)stalloc(sizeof (struct nbinary));
+ n3->type = NSEMI;
+ n3->nbinary.ch1 = n1;
+ n3->nbinary.ch2 = n2;
+ n1 = n3;
+ }
+ switch (tok) {
+ case TBACKGND:
+ case TSEMI:
+ tok = readtoken();
+ /* fall through */
+ case TNL:
+ if (tok == TNL) {
+ parseheredoc();
+ if (nlflag == 1)
+ return n1;
+ } else {
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (tokendlist[peektoken()])
+ return n1;
+ break;
+ case TEOF:
+ if (heredoclist)
+ parseheredoc();
+ else
+ pungetc(); /* push back EOF on input */
+ return n1;
+ default:
+ if (nlflag == 1)
+ synexpect(-1);
+ tokpushback++;
+ return n1;
+ }
+ }
+}
+
+
+
+STATIC union node *
+andor(void)
+{
+ union node *n1, *n2, *n3;
+ int t;
+
+ n1 = pipeline();
+ for (;;) {
+ if ((t = readtoken()) == TAND) {
+ t = NAND;
+ } else if (t == TOR) {
+ t = NOR;
+ } else {
+ tokpushback++;
+ return n1;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ n2 = pipeline();
+ n3 = (union node *)stalloc(sizeof (struct nbinary));
+ n3->type = t;
+ n3->nbinary.ch1 = n1;
+ n3->nbinary.ch2 = n2;
+ n1 = n3;
+ }
+}
+
+
+
+STATIC union node *
+pipeline(void)
+{
+ union node *n1, *n2, *pipenode;
+ struct nodelist *lp, *prev;
+ int negate;
+
+ negate = 0;
+ TRACE(("pipeline: entered\n"));
+ if (readtoken() == TNOT) {
+ negate = !negate;
+ checkkwd = CHKKWD | CHKALIAS;
+ } else
+ tokpushback++;
+ n1 = command();
+ if (readtoken() == TPIPE) {
+ pipenode = (union node *)stalloc(sizeof (struct npipe));
+ pipenode->type = NPIPE;
+ pipenode->npipe.backgnd = 0;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ pipenode->npipe.cmdlist = lp;
+ lp->n = n1;
+ do {
+ prev = lp;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ lp->n = command();
+ prev->next = lp;
+ } while (readtoken() == TPIPE);
+ lp->next = NULL;
+ n1 = pipenode;
+ }
+ tokpushback++;
+ if (negate) {
+ n2 = (union node *)stalloc(sizeof (struct nnot));
+ n2->type = NNOT;
+ n2->nnot.com = n1;
+ return n2;
+ } else
+ return n1;
+}
+
+
+
+STATIC union node *
+command(void)
+{
+ union node *n1, *n2;
+ union node *ap, **app;
+ union node *cp, **cpp;
+ union node *redir, **rpp;
+ union node **rpp2;
+ int t;
+ int savelinno;
+
+ redir = NULL;
+ rpp2 = &redir;
+
+ savelinno = plinno;
+
+ switch (readtoken()) {
+ default:
+ synexpect(-1);
+ /* NOTREACHED */
+ case TIF:
+ n1 = (union node *)stalloc(sizeof (struct nif));
+ n1->type = NIF;
+ n1->nif.test = list(0);
+ if (readtoken() != TTHEN)
+ synexpect(TTHEN);
+ n1->nif.ifpart = list(0);
+ n2 = n1;
+ while (readtoken() == TELIF) {
+ n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+ n2 = n2->nif.elsepart;
+ n2->type = NIF;
+ n2->nif.test = list(0);
+ if (readtoken() != TTHEN)
+ synexpect(TTHEN);
+ n2->nif.ifpart = list(0);
+ }
+ if (lasttoken == TELSE)
+ n2->nif.elsepart = list(0);
+ else {
+ n2->nif.elsepart = NULL;
+ tokpushback++;
+ }
+ t = TFI;
+ break;
+ case TWHILE:
+ case TUNTIL: {
+ int got;
+ n1 = (union node *)stalloc(sizeof (struct nbinary));
+ n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
+ n1->nbinary.ch1 = list(0);
+ if ((got=readtoken()) != TDO) {
+TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
+ synexpect(TDO);
+ }
+ n1->nbinary.ch2 = list(0);
+ t = TDONE;
+ break;
+ }
+ case TFOR:
+ if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+ synerror("Bad for loop variable");
+ n1 = (union node *)stalloc(sizeof (struct nfor));
+ n1->type = NFOR;
+ n1->nfor.linno = savelinno;
+ n1->nfor.var = wordtext;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (readtoken() == TIN) {
+ app = &ap;
+ while (readtoken() == TWORD) {
+ n2 = (union node *)stalloc(sizeof (struct narg));
+ n2->type = NARG;
+ n2->narg.text = wordtext;
+ n2->narg.backquote = backquotelist;
+ *app = n2;
+ app = &n2->narg.next;
+ }
+ *app = NULL;
+ n1->nfor.args = ap;
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ synexpect(-1);
+ } else {
+ n2 = (union node *)stalloc(sizeof (struct narg));
+ n2->type = NARG;
+ n2->narg.text = (char *)dolatstr;
+ n2->narg.backquote = NULL;
+ n2->narg.next = NULL;
+ n1->nfor.args = n2;
+ /*
+ * Newline or semicolon here is optional (but note
+ * that the original Bourne shell only allowed NL).
+ */
+ if (lasttoken != TSEMI)
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (readtoken() != TDO)
+ synexpect(TDO);
+ n1->nfor.body = list(0);
+ t = TDONE;
+ break;
+ case TCASE:
+ n1 = (union node *)stalloc(sizeof (struct ncase));
+ n1->type = NCASE;
+ n1->ncase.linno = savelinno;
+ if (readtoken() != TWORD)
+ synexpect(TWORD);
+ n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
+ n2->type = NARG;
+ n2->narg.text = wordtext;
+ n2->narg.backquote = backquotelist;
+ n2->narg.next = NULL;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (readtoken() != TIN)
+ synexpect(TIN);
+ cpp = &n1->ncase.cases;
+next_case:
+ checkkwd = CHKNL | CHKKWD;
+ t = readtoken();
+ while(t != TESAC) {
+ if (lasttoken == TLP)
+ readtoken();
+ *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+ cp->type = NCLIST;
+ app = &cp->nclist.pattern;
+ for (;;) {
+ *app = ap = (union node *)stalloc(sizeof (struct narg));
+ ap->type = NARG;
+ ap->narg.text = wordtext;
+ ap->narg.backquote = backquotelist;
+ if (readtoken() != TPIPE)
+ break;
+ app = &ap->narg.next;
+ readtoken();
+ }
+ ap->narg.next = NULL;
+ if (lasttoken != TRP)
+ synexpect(TRP);
+ cp->nclist.body = list(2);
+
+ cpp = &cp->nclist.next;
+
+ checkkwd = CHKNL | CHKKWD;
+ if ((t = readtoken()) != TESAC) {
+ if (t != TENDCASE)
+ synexpect(TENDCASE);
+ else
+ goto next_case;
+ }
+ }
+ *cpp = NULL;
+ goto redir;
+ case TLP:
+ n1 = (union node *)stalloc(sizeof (struct nredir));
+ n1->type = NSUBSHELL;
+ n1->nredir.linno = savelinno;
+ n1->nredir.n = list(0);
+ n1->nredir.redirect = NULL;
+ t = TRP;
+ break;
+ case TBEGIN:
+ n1 = list(0);
+ t = TEND;
+ break;
+ case TWORD:
+ case TREDIR:
+ tokpushback++;
+ return simplecmd();
+ }
+
+ if (readtoken() != t)
+ synexpect(t);
+
+redir:
+ /* Now check for redirection which may follow command */
+ checkkwd = CHKKWD | CHKALIAS;
+ rpp = rpp2;
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+ *rpp = NULL;
+ if (redir) {
+ if (n1->type != NSUBSHELL) {
+ n2 = (union node *)stalloc(sizeof (struct nredir));
+ n2->type = NREDIR;
+ n2->nredir.linno = savelinno;
+ n2->nredir.n = n1;
+ n1 = n2;
+ }
+ n1->nredir.redirect = redir;
+ }
+
+ return n1;
+}
+
+
+STATIC union node *
+simplecmd(void) {
+ union node *args, **app;
+ union node *n = NULL;
+ union node *vars, **vpp;
+ union node **rpp, *redir;
+ int savecheckkwd;
+ int savelinno;
+
+ args = NULL;
+ app = &args;
+ vars = NULL;
+ vpp = &vars;
+ redir = NULL;
+ rpp = &redir;
+
+ savecheckkwd = CHKALIAS;
+ savelinno = plinno;
+ for (;;) {
+ checkkwd = savecheckkwd;
+ switch (readtoken()) {
+ case TWORD:
+ n = (union node *)stalloc(sizeof (struct narg));
+ n->type = NARG;
+ n->narg.text = wordtext;
+ n->narg.backquote = backquotelist;
+ if (savecheckkwd && isassignment(wordtext)) {
+ *vpp = n;
+ vpp = &n->narg.next;
+ } else {
+ *app = n;
+ app = &n->narg.next;
+ savecheckkwd = 0;
+ }
+ break;
+ case TREDIR:
+ *rpp = n = redirnode;
+ rpp = &n->nfile.next;
+ parsefname(); /* read name of redirection file */
+ break;
+ case TLP:
+ if (
+ args && app == &args->narg.next &&
+ !vars && !redir
+ ) {
+ struct builtincmd *bcmd;
+ const char *name;
+
+ /* We have a function */
+ if (readtoken() != TRP)
+ synexpect(TRP);
+ name = n->narg.text;
+ if (
+ !goodname(name) || (
+ (bcmd = find_builtin(name)) &&
+ bcmd->flags & BUILTIN_SPECIAL
+ )
+ )
+ synerror("Bad function name");
+ n->type = NDEFUN;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ n->ndefun.text = n->narg.text;
+ n->ndefun.linno = plinno;
+ n->ndefun.body = command();
+ return n;
+ }
+ /* fall through */
+ default:
+ tokpushback++;
+ goto out;
+ }
+ }
+out:
+ *app = NULL;
+ *vpp = NULL;
+ *rpp = NULL;
+ n = (union node *)stalloc(sizeof (struct ncmd));
+ n->type = NCMD;
+ n->ncmd.linno = savelinno;
+ n->ncmd.args = args;
+ n->ncmd.assign = vars;
+ n->ncmd.redirect = redir;
+ return n;
+}
+
+STATIC union node *
+makename(void)
+{
+ union node *n;
+
+ n = (union node *)stalloc(sizeof (struct narg));
+ n->type = NARG;
+ n->narg.next = NULL;
+ n->narg.text = wordtext;
+ n->narg.backquote = backquotelist;
+ return n;
+}
+
+void fixredir(union node *n, const char *text, int err)
+ {
+ TRACE(("Fix redir %s %d\n", text, err));
+ if (!err)
+ n->ndup.vname = NULL;
+
+ if (is_digit(text[0]) && text[1] == '\0')
+ n->ndup.dupfd = digit_val(text[0]);
+ else if (text[0] == '-' && text[1] == '\0')
+ n->ndup.dupfd = -1;
+ else {
+
+ if (err)
+ synerror("Bad fd number");
+ else
+ n->ndup.vname = makename();
+ }
+}
+
+
+STATIC void
+parsefname(void)
+{
+ union node *n = redirnode;
+
+ if (n->type == NHERE)
+ checkkwd = CHKEOFMARK;
+ if (readtoken() != TWORD)
+ synexpect(-1);
+ if (n->type == NHERE) {
+ struct heredoc *here = heredoc;
+ struct heredoc *p;
+
+ if (quoteflag == 0)
+ n->type = NXHERE;
+ TRACE(("Here document %d\n", n->type));
+ rmescapes(wordtext);
+ here->eofmark = wordtext;
+ here->next = NULL;
+ if (heredoclist == NULL)
+ heredoclist = here;
+ else {
+ for (p = heredoclist ; p->next ; p = p->next);
+ p->next = here;
+ }
+ } else if (n->type == NTOFD || n->type == NFROMFD) {
+ fixredir(n, wordtext, 0);
+ } else {
+ n->nfile.fname = makename();
+ }
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+STATIC void
+parseheredoc(void)
+{
+ struct heredoc *here;
+ union node *n;
+
+ here = heredoclist;
+ heredoclist = 0;
+
+ while (here) {
+ if (needprompt) {
+ setprompt(2);
+ }
+ readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+ here->eofmark, here->striptabs);
+ n = (union node *)stalloc(sizeof (struct narg));
+ n->narg.type = NARG;
+ n->narg.next = NULL;
+ n->narg.text = wordtext;
+ n->narg.backquote = backquotelist;
+ here->here->nhere.doc = n;
+ here = here->next;
+ }
+}
+
+STATIC int
+peektoken(void)
+{
+ int t;
+
+ t = readtoken();
+ tokpushback++;
+ return (t);
+}
+
+STATIC int
+readtoken(void)
+{
+ int t;
+ int kwd = checkkwd;
+#ifdef DEBUG
+ int alreadyseen = tokpushback;
+#endif
+
+top:
+ t = xxreadtoken();
+
+ /*
+ * eat newlines
+ */
+ if (kwd & CHKNL) {
+ while (t == TNL) {
+ parseheredoc();
+ t = xxreadtoken();
+ }
+ }
+
+ if (t != TWORD || quoteflag) {
+ goto out;
+ }
+
+ /*
+ * check for keywords
+ */
+ if (kwd & CHKKWD) {
+ const char *const *pp;
+
+ if ((pp = findkwd(wordtext))) {
+ lasttoken = t = pp - parsekwd + KWDOFFSET;
+ TRACE(("keyword %s recognized\n", tokname[t]));
+ goto out;
+ }
+ }
+
+ if (checkkwd & CHKALIAS) {
+ struct alias *ap;
+ if ((ap = lookupalias(wordtext, 1)) != NULL) {
+ if (*ap->val) {
+ pushstring(ap->val, ap);
+ }
+ goto top;
+ }
+ }
+out:
+ checkkwd = 0;
+#ifdef DEBUG
+ if (!alreadyseen)
+ TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+ else
+ TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+#endif
+ return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ * backquotes. We set quoteflag to true if any part of the word was
+ * quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ * the redirection.
+ *
+ * [Change comment: here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments. Perhaps we should make the
+ * word parsing code into a separate routine. In this case, readtoken
+ * doesn't need to have any internal procedures, but parseword does.
+ * We could also make parseoperator in essence the main routine, and
+ * have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define RETURN(token) return lasttoken = token
+
+STATIC int
+xxreadtoken(void)
+{
+ int c;
+
+ if (tokpushback) {
+ tokpushback = 0;
+ return lasttoken;
+ }
+ if (needprompt) {
+ setprompt(2);
+ }
+ for (;;) { /* until token or start of word found */
+ c = pgetc_macro();
+ switch (c) {
+ case ' ': case '\t':
+ case PEOA:
+ continue;
+ case '#':
+ while ((c = pgetc()) != '\n' && c != PEOF);
+ pungetc();
+ continue;
+ case '\\':
+ if (pgetc() == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ continue;
+ }
+ pungetc();
+ goto breakloop;
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ RETURN(TNL);
+ case PEOF:
+ RETURN(TEOF);
+ case '&':
+ if (pgetc() == '&')
+ RETURN(TAND);
+ pungetc();
+ RETURN(TBACKGND);
+ case '|':
+ if (pgetc() == '|')
+ RETURN(TOR);
+ pungetc();
+ RETURN(TPIPE);
+ case ';':
+ if (pgetc() == ';')
+ RETURN(TENDCASE);
+ pungetc();
+ RETURN(TSEMI);
+ case '(':
+ RETURN(TLP);
+ case ')':
+ RETURN(TRP);
+ default:
+ goto breakloop;
+ }
+ }
+breakloop:
+ return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+#undef RETURN
+}
+
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol. If eofmark
+ * is not NULL, read a here document. In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document. The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage. The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define CHECKEND() {goto checkend; checkend_return:;}
+#define PARSEREDIR() {goto parseredir; parseredir_return:;}
+#define PARSESUB() {goto parsesub; parsesub_return:;}
+#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
+#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
+#define PARSEARITH() {goto parsearith; parsearith_return:;}
+
+STATIC int
+readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
+{
+ int c = firstc;
+ char *out;
+ size_t len;
+ struct nodelist *bqlist;
+ int quotef;
+ int dblquote;
+ int varnest; /* levels of variables expansion */
+ int arinest; /* levels of arithmetic expansion */
+ int parenlevel; /* levels of parens in arithmetic */
+ int dqvarnest; /* levels of variables expansion within double quotes */
+ int oldstyle;
+ /* syntax before arithmetic */
+ char const *uninitialized_var(prevsyntax);
+
+ dblquote = 0;
+ if (syntax == DQSYNTAX)
+ dblquote = 1;
+ quotef = 0;
+ bqlist = NULL;
+ varnest = 0;
+ arinest = 0;
+ parenlevel = 0;
+ dqvarnest = 0;
+
+ STARTSTACKSTR(out);
+ loop: { /* for each line, until end of word */
+#if ATTY
+ if (c == '\034' && doprompt
+ && attyset() && ! equal(termval(), "emacs")) {
+ attyline();
+ if (syntax == BASESYNTAX)
+ return readtoken();
+ c = pgetc();
+ goto loop;
+ }
+#endif
+ CHECKEND(); /* set c to PEOF if at end of here document */
+ for (;;) { /* until end of line or end of word */
+ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
+ switch(syntax[c]) {
+ case CNL: /* '\n' */
+ if (syntax == BASESYNTAX)
+ goto endword; /* exit outer loop */
+ USTPUTC(c, out);
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ c = pgetc();
+ goto loop; /* continue outer loop */
+ case CWORD:
+ USTPUTC(c, out);
+ break;
+ case CCTL:
+ if (eofmark == NULL || dblquote)
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ break;
+ /* backslash */
+ case CBACK:
+ c = pgetc2();
+ if (c == PEOF) {
+ USTPUTC(CTLESC, out);
+ USTPUTC('\\', out);
+ pungetc();
+ } else if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ } else {
+ if (
+ dblquote &&
+ c != '\\' && c != '`' &&
+ c != '$' && (
+ c != '"' ||
+ eofmark != NULL
+ )
+ ) {
+ USTPUTC('\\', out);
+ }
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ quotef++;
+ }
+ break;
+ case CSQUOTE:
+ syntax = SQSYNTAX;
+quotemark:
+ if (eofmark == NULL) {
+ USTPUTC(CTLQUOTEMARK, out);
+ }
+ break;
+ case CDQUOTE:
+ syntax = DQSYNTAX;
+ dblquote = 1;
+ goto quotemark;
+ case CENDQUOTE:
+ if (eofmark && !varnest)
+ USTPUTC(c, out);
+ else {
+ if (dqvarnest == 0) {
+ syntax = BASESYNTAX;
+ dblquote = 0;
+ }
+ quotef++;
+ goto quotemark;
+ }
+ break;
+ case CVAR: /* '$' */
+ PARSESUB(); /* parse substitution */
+ break;
+ case CENDVAR: /* '}' */
+ if (varnest > 0) {
+ varnest--;
+ if (dqvarnest > 0) {
+ dqvarnest--;
+ }
+ USTPUTC(CTLENDVAR, out);
+ } else {
+ USTPUTC(c, out);
+ }
+ break;
+ case CLP: /* '(' in arithmetic */
+ parenlevel++;
+ USTPUTC(c, out);
+ break;
+ case CRP: /* ')' in arithmetic */
+ if (parenlevel > 0) {
+ USTPUTC(c, out);
+ --parenlevel;
+ } else {
+ if (pgetc() == ')') {
+ USTPUTC(CTLENDARI, out);
+ if (!--arinest)
+ syntax = prevsyntax;
+ } else {
+ /*
+ * unbalanced parens
+ * (don't 2nd guess - no error)
+ */
+ pungetc();
+ USTPUTC(')', out);
+ }
+ }
+ break;
+ case CBQUOTE: /* '`' */
+ PARSEBACKQOLD();
+ break;
+ case CEOF:
+ goto endword; /* exit outer loop */
+ case CIGN:
+ break;
+ default:
+ if (varnest == 0)
+ goto endword; /* exit outer loop */
+ if (c != PEOA) {
+ USTPUTC(c, out);
+ }
+ }
+ c = pgetc_macro();
+ }
+ }
+endword:
+ if (syntax == ARISYNTAX)
+ synerror("Missing '))'");
+ if (syntax != BASESYNTAX && eofmark == NULL)
+ synerror("Unterminated quoted string");
+ if (varnest != 0) {
+ /* { */
+ synerror("Missing '}'");
+ }
+ USTPUTC('\0', out);
+ len = out - (char *)stackblock();
+ out = stackblock();
+ if (eofmark == NULL) {
+ if ((c == '>' || c == '<')
+ && quotef == 0
+ && len <= 2
+ && (*out == '\0' || is_digit(*out))) {
+ PARSEREDIR();
+ return lasttoken = TREDIR;
+ } else {
+ pungetc();
+ }
+ }
+ quoteflag = quotef;
+ backquotelist = bqlist;
+ grabstackblock(len);
+ wordtext = out;
+ return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+
+/*
+ * Check to see whether we are at the end of the here document. When this
+ * is called, c is set to the first character of the next input line. If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ */
+
+checkend: {
+ if (realeofmark(eofmark)) {
+ int markloc;
+ char *p;
+
+ if (c == PEOA) {
+ c = pgetc2();
+ }
+ if (striptabs) {
+ while (c == '\t') {
+ c = pgetc2();
+ }
+ }
+
+ markloc = out - (char *)stackblock();
+ for (p = eofmark; STPUTC(c, out), *p; p++) {
+ if (c != *p)
+ goto more_heredoc;
+
+ c = pgetc2();
+ }
+
+ if (c == '\n' || c == PEOF) {
+ c = PEOF;
+ plinno++;
+ needprompt = doprompt;
+ } else {
+ int len;
+
+more_heredoc:
+ p = (char *)stackblock() + markloc + 1;
+ len = out - p;
+
+ if (len) {
+ len -= c < 0;
+ c = p[-1];
+
+ if (len) {
+ char *str;
+
+ str = alloca(len + 1);
+ *(char *)mempcpy(str, p, len) = 0;
+
+ pushstring(str, NULL);
+ }
+ }
+ }
+
+ STADJUST((char *)stackblock() + markloc - out, out);
+ }
+ goto checkend_return;
+}
+
+
+/*
+ * Parse a redirection operator. The variable "out" points to a string
+ * specifying the fd to be redirected. The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+parseredir: {
+ char fd = *out;
+ union node *np;
+
+ np = (union node *)stalloc(sizeof (struct nfile));
+ if (c == '>') {
+ np->nfile.fd = 1;
+ c = pgetc();
+ if (c == '>')
+ np->type = NAPPEND;
+ else if (c == '|')
+ np->type = NCLOBBER;
+ else if (c == '&')
+ np->type = NTOFD;
+ else {
+ np->type = NTO;
+ pungetc();
+ }
+ } else { /* c == '<' */
+ np->nfile.fd = 0;
+ switch (c = pgetc()) {
+ case '<':
+ if (sizeof (struct nfile) != sizeof (struct nhere)) {
+ np = (union node *)stalloc(sizeof (struct nhere));
+ np->nfile.fd = 0;
+ }
+ np->type = NHERE;
+ heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+ heredoc->here = np;
+ if ((c = pgetc()) == '-') {
+ heredoc->striptabs = 1;
+ } else {
+ heredoc->striptabs = 0;
+ pungetc();
+ }
+ break;
+
+ case '&':
+ np->type = NFROMFD;
+ break;
+
+ case '>':
+ np->type = NFROMTO;
+ break;
+
+ default:
+ np->type = NFROM;
+ pungetc();
+ break;
+ }
+ }
+ if (fd != '\0')
+ np->nfile.fd = digit_val(fd);
+ redirnode = np;
+ goto parseredir_return;
+}
+
+
+/*
+ * Parse a substitution. At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+ int subtype;
+ int typeloc;
+ char *p;
+ static const char types[] = "}-+?=";
+
+ c = pgetc();
+ if (
+ (checkkwd & CHKEOFMARK) ||
+ c <= PEOA ||
+ (c != '(' && c != '{' && !is_name(c) && !is_special(c))
+ ) {
+ USTPUTC('$', out);
+ pungetc();
+ } else if (c == '(') { /* $(command) or $((arith)) */
+ if (pgetc() == '(') {
+ PARSEARITH();
+ } else {
+ pungetc();
+ PARSEBACKQNEW();
+ }
+ } else {
+ USTPUTC(CTLVAR, out);
+ typeloc = out - (char *)stackblock();
+ STADJUST(1, out);
+ subtype = VSNORMAL;
+ if (likely(c == '{')) {
+ c = pgetc();
+ subtype = 0;
+ }
+varname:
+ if (is_name(c)) {
+ do {
+ STPUTC(c, out);
+ c = pgetc();
+ } while (is_in_name(c));
+ } else if (is_digit(c)) {
+ do {
+ STPUTC(c, out);
+ c = pgetc();
+ } while (is_digit(c));
+ }
+ else if (is_special(c)) {
+ int cc = c;
+
+ c = pgetc();
+
+ if (!subtype && cc == '#') {
+ subtype = VSLENGTH;
+
+ if (c == '_' || isalnum(c))
+ goto varname;
+
+ cc = c;
+ c = pgetc();
+ if (cc == '}' || c != '}') {
+ pungetc();
+ subtype = 0;
+ c = cc;
+ cc = '#';
+ }
+ }
+
+ USTPUTC(cc, out);
+ }
+ else
+ goto badsub;
+
+ if (subtype == 0) {
+ switch (c) {
+ case ':':
+ subtype = VSNUL;
+ c = pgetc();
+ /*FALLTHROUGH*/
+ default:
+ p = strchr(types, c);
+ if (p == NULL)
+ break;
+ subtype |= p - types + VSNORMAL;
+ break;
+ case '%':
+ case '#':
+ {
+ int cc = c;
+ subtype = c == '#' ? VSTRIMLEFT :
+ VSTRIMRIGHT;
+ c = pgetc();
+ if (c == cc)
+ subtype++;
+ else
+ pungetc();
+ break;
+ }
+ }
+ } else {
+badsub:
+ pungetc();
+ }
+ *((char *)stackblock() + typeloc) = subtype;
+ if (subtype != VSNORMAL) {
+ varnest++;
+ if (dblquote)
+ dqvarnest++;
+ }
+ STPUTC('=', out);
+ }
+ goto parsesub_return;
+}
+
+
+/*
+ * Called to parse command substitutions. Newstyle is set if the command
+ * is enclosed inside $(...); nlpp is a pointer to the head of the linked
+ * list of commands (passed by reference), and savelen is the number of
+ * characters on the top of the stack which must be preserved.
+ */
+
+parsebackq: {
+ struct nodelist **nlpp;
+ union node *n;
+ char *str;
+ size_t savelen;
+ int uninitialized_var(saveprompt);
+
+ str = NULL;
+ savelen = out - (char *)stackblock();
+ if (savelen > 0) {
+ str = alloca(savelen);
+ memcpy(str, stackblock(), savelen);
+ }
+ if (oldstyle) {
+ /* We must read until the closing backquote, giving special
+ treatment to some slashes, and then push the string and
+ reread it as input, interpreting it normally. */
+ char *pout;
+ int pc;
+ size_t psavelen;
+ char *pstr;
+
+
+ STARTSTACKSTR(pout);
+ for (;;) {
+ if (needprompt) {
+ setprompt(2);
+ }
+ switch (pc = pgetc()) {
+ case '`':
+ goto done;
+
+ case '\\':
+ if ((pc = pgetc()) == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ /*
+ * If eating a newline, avoid putting
+ * the newline into the new character
+ * stream (via the STPUTC after the
+ * switch).
+ */
+ continue;
+ }
+ if (pc != '\\' && pc != '`' && pc != '$'
+ && (!dblquote || pc != '"'))
+ STPUTC('\\', pout);
+ if (pc > PEOA) {
+ break;
+ }
+ /* fall through */
+
+ case PEOF:
+ case PEOA:
+ synerror("EOF in backquote substitution");
+
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ break;
+
+ default:
+ break;
+ }
+ STPUTC(pc, pout);
+ }
+done:
+ STPUTC('\0', pout);
+ psavelen = pout - (char *)stackblock();
+ if (psavelen > 0) {
+ pstr = grabstackstr(pout);
+ setinputstring(pstr);
+ }
+ }
+ nlpp = &bqlist;
+ while (*nlpp)
+ nlpp = &(*nlpp)->next;
+ *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ (*nlpp)->next = NULL;
+
+ if (oldstyle) {
+ saveprompt = doprompt;
+ doprompt = 0;
+ }
+
+ n = list(2);
+
+ if (oldstyle)
+ doprompt = saveprompt;
+ else {
+ if (readtoken() != TRP)
+ synexpect(TRP);
+ }
+
+ (*nlpp)->n = n;
+ if (oldstyle) {
+ /*
+ * Start reading from old file again, ignoring any pushed back
+ * tokens left from the backquote parsing
+ */
+ popfile();
+ tokpushback = 0;
+ }
+ while (stackblocksize() <= savelen)
+ growstackblock();
+ STARTSTACKSTR(out);
+ if (str) {
+ memcpy(out, str, savelen);
+ STADJUST(savelen, out);
+ }
+ USTPUTC(CTLBACKQ, out);
+ if (oldstyle)
+ goto parsebackq_oldreturn;
+ else
+ goto parsebackq_newreturn;
+}
+
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+ if (++arinest == 1) {
+ prevsyntax = syntax;
+ syntax = ARISYNTAX;
+ }
+ USTPUTC(CTLARI, out);
+ goto parsearith_return;
+}
+
+} /* end of readtoken */
+
+
+
+#ifdef mkinit
+INCLUDE "parser.h"
+RESET {
+ tokpushback = 0;
+ checkkwd = 0;
+}
+#endif
+
+
+/*
+ * Return of a legal variable name (a letter or underscore followed by zero or
+ * more letters, underscores, and digits).
+ */
+
+char *
+endofname(const char *name)
+ {
+ char *p;
+
+ p = (char *) name;
+ if (! is_name(*p))
+ return p;
+ while (*++p) {
+ if (! is_in_name(*p))
+ break;
+ }
+ return p;
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse. The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+STATIC void
+synexpect(int token)
+{
+ char msg[64];
+
+ if (token >= 0) {
+ fmtstr(msg, 64, "%s unexpected (expecting %s)",
+ tokname[lasttoken], tokname[token]);
+ } else {
+ fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+ }
+ synerror(msg);
+ /* NOTREACHED */
+}
+
+
+STATIC void
+synerror(const char *msg)
+{
+ errlinno = plinno;
+ sh_error("Syntax error: %s", msg);
+ /* NOTREACHED */
+}
+
+STATIC void
+setprompt(int which)
+{
+ struct stackmark smark;
+ int show;
+
+ needprompt = 0;
+ whichprompt = which;
+
+#ifdef SMALL
+ show = 1;
+#else
+ show = !el;
+#endif
+ if (show) {
+ pushstackmark(&smark, stackblocksize());
+ out2str(getprompt(NULL));
+ popstackmark(&smark);
+ }
+}
+
+const char *
+expandstr(const char *ps)
+{
+ union node n;
+ int saveprompt;
+
+ /* XXX Fix (char *) cast. */
+ setinputstring((char *)ps);
+
+ saveprompt = doprompt;
+ doprompt = 0;
+
+ readtoken1(pgetc(), DQSYNTAX, FAKEEOFMARK, 0);
+
+ doprompt = saveprompt;
+
+ popfile();
+
+ n.narg.type = NARG;
+ n.narg.next = NULL;
+ n.narg.text = wordtext;
+ n.narg.backquote = backquotelist;
+
+ expandarg(&n, NULL, EXP_QUOTED);
+ return stackblock();
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ * should be added here.
+ */
+const char *
+getprompt(void *unused)
+{
+ const char *prompt;
+
+ switch (whichprompt) {
+ default:
+#ifdef DEBUG
+ return "<internal prompt error>";
+#endif
+ case 0:
+ return nullstr;
+ case 1:
+ prompt = ps1val();
+ break;
+ case 2:
+ prompt = ps2val();
+ break;
+ }
+
+ return expandstr(prompt);
+}
+
+const char *const *
+findkwd(const char *s)
+{
+ return findstring(
+ s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
+ );
+}
diff --git a/usr/dash/parser.h b/usr/dash/parser.h
new file mode 100644
index 0000000..e6caed6
--- /dev/null
+++ b/usr/dash/parser.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)parser.h 8.3 (Berkeley) 5/4/95
+ */
+
+/* control characters in argument strings */
+#define CTL_FIRST -127 /* first 'special' character */
+#define CTLESC -127 /* escape next character */
+#define CTLVAR -126 /* variable defn */
+#define CTLENDVAR -125
+#define CTLBACKQ -124
+#define CTLARI -122 /* arithmetic expression */
+#define CTLENDARI -121
+#define CTLQUOTEMARK -120
+#define CTL_LAST -120 /* last 'special' character */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE 0x0f /* type of variable substitution */
+#define VSNUL 0x10 /* colon--treat the empty string as unset */
+
+/* values of VSTYPE field */
+#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
+#define VSMINUS 0x2 /* ${var-text} */
+#define VSPLUS 0x3 /* ${var+text} */
+#define VSQUESTION 0x4 /* ${var?message} */
+#define VSASSIGN 0x5 /* ${var=text} */
+#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
+#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
+#define VSTRIMLEFT 0x8 /* ${var#pattern} */
+#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
+#define VSLENGTH 0xa /* ${#var} */
+
+/* values of checkkwd variable */
+#define CHKALIAS 0x1
+#define CHKKWD 0x2
+#define CHKNL 0x4
+#define CHKEOFMARK 0x8
+
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file. It
+ * must be distinct from NULL, so we use the address of a variable that
+ * happens to be handy.
+ */
+extern int tokpushback;
+#define NEOF ((union node *)&tokpushback)
+extern int whichprompt; /* 1 == PS1, 2 == PS2 */
+extern int checkkwd;
+
+
+union node *parsecmd(int);
+void fixredir(union node *, const char *, int);
+const char *getprompt(void *);
+const char *const *findkwd(const char *);
+char *endofname(const char *);
+const char *expandstr(const char *);
+
+static inline int
+goodname(const char *p)
+{
+ return !*endofname(p);
+}
diff --git a/usr/dash/redir.c b/usr/dash/redir.c
new file mode 100644
index 0000000..f96a76b
--- /dev/null
+++ b/usr/dash/redir.c
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h> /* PIPE_BUF */
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#include "main.h"
+#include "shell.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "expand.h"
+#include "redir.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+
+
+#define REALLY_CLOSED -3 /* fd that was closed and still is */
+#define EMPTY -2 /* marks an unused slot in redirtab */
+#define CLOSED -1 /* fd opened for redir needs to be closed */
+
+#ifndef PIPE_BUF
+# define PIPESIZE 4096 /* amount of buffering in a pipe */
+#else
+# define PIPESIZE PIPE_BUF
+#endif
+
+
+MKINIT
+struct redirtab {
+ struct redirtab *next;
+ int renamed[10];
+};
+
+
+MKINIT struct redirtab *redirlist;
+
+STATIC int openredirect(union node *);
+#ifdef notyet
+STATIC void dupredirect(union node *, int, char[10]);
+#else
+STATIC void dupredirect(union node *, int);
+#endif
+STATIC int openhere(union node *);
+
+
+/*
+ * Process a list of redirection commands. If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+ */
+
+void
+redirect(union node *redir, int flags)
+{
+ union node *n;
+ struct redirtab *sv;
+ int i;
+ int fd;
+ int newfd;
+ int *p;
+#if notyet
+ char memory[10]; /* file descriptors to write to memory */
+
+ for (i = 10 ; --i >= 0 ; )
+ memory[i] = 0;
+ memory[1] = flags & REDIR_BACKQ;
+#endif
+ if (!redir)
+ return;
+ sv = NULL;
+ INTOFF;
+ if (likely(flags & REDIR_PUSH))
+ sv = redirlist;
+ n = redir;
+ do {
+ newfd = openredirect(n);
+ if (newfd < -1)
+ continue;
+
+ fd = n->nfile.fd;
+
+ if (sv) {
+ p = &sv->renamed[fd];
+ i = *p;
+
+ if (likely(i == EMPTY)) {
+ i = CLOSED;
+ if (fd != newfd) {
+ i = savefd(fd, fd);
+ fd = -1;
+ }
+ }
+
+ if (i == newfd)
+ /* Can only happen if i == newfd == CLOSED */
+ i = REALLY_CLOSED;
+
+ *p = i;
+ }
+
+ if (fd == newfd)
+ continue;
+
+#ifdef notyet
+ dupredirect(n, newfd, memory);
+#else
+ dupredirect(n, newfd);
+#endif
+ } while ((n = n->nfile.next));
+ INTON;
+#ifdef notyet
+ if (memory[1])
+ out1 = &memout;
+ if (memory[2])
+ out2 = &memout;
+#endif
+ if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0)
+ preverrout.fd = sv->renamed[2];
+}
+
+
+STATIC int
+openredirect(union node *redir)
+{
+ struct stat64 sb;
+ char *fname;
+ int f;
+
+ switch (redir->nfile.type) {
+ case NFROM:
+ fname = redir->nfile.expfname;
+ if ((f = open64(fname, O_RDONLY)) < 0)
+ goto eopen;
+ break;
+ case NFROMTO:
+ fname = redir->nfile.expfname;
+ if ((f = open64(fname, O_RDWR|O_CREAT, 0666)) < 0)
+ goto ecreate;
+ break;
+ case NTO:
+ /* Take care of noclobber mode. */
+ if (Cflag) {
+ fname = redir->nfile.expfname;
+ if (stat64(fname, &sb) < 0) {
+ if ((f = open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
+ goto ecreate;
+ } else if (!S_ISREG(sb.st_mode)) {
+ if ((f = open64(fname, O_WRONLY, 0666)) < 0)
+ goto ecreate;
+ if (fstat64(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
+ close(f);
+ errno = EEXIST;
+ goto ecreate;
+ }
+ } else {
+ errno = EEXIST;
+ goto ecreate;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case NCLOBBER:
+ fname = redir->nfile.expfname;
+ if ((f = open64(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+ goto ecreate;
+ break;
+ case NAPPEND:
+ fname = redir->nfile.expfname;
+ if ((f = open64(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+ goto ecreate;
+ break;
+ case NTOFD:
+ case NFROMFD:
+ f = redir->ndup.dupfd;
+ if (f == redir->nfile.fd)
+ f = -2;
+ break;
+ default:
+#ifdef DEBUG
+ abort();
+#endif
+ /* Fall through to eliminate warning. */
+ case NHERE:
+ case NXHERE:
+ f = openhere(redir);
+ break;
+ }
+
+ return f;
+ecreate:
+ sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+ sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
+}
+
+
+STATIC void
+#ifdef notyet
+dupredirect(redir, f, memory)
+#else
+dupredirect(redir, f)
+#endif
+ union node *redir;
+ int f;
+#ifdef notyet
+ char memory[10];
+#endif
+ {
+ int fd = redir->nfile.fd;
+ int err = 0;
+
+#ifdef notyet
+ memory[fd] = 0;
+#endif
+ if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
+ /* if not ">&-" */
+ if (f >= 0) {
+#ifdef notyet
+ if (memory[f])
+ memory[fd] = 1;
+ else
+#endif
+ if (dup2(f, fd) < 0) {
+ err = errno;
+ goto err;
+ }
+ return;
+ }
+ f = fd;
+ } else if (dup2(f, fd) < 0)
+ err = errno;
+
+ close(f);
+ if (err < 0)
+ goto err;
+
+ return;
+
+err:
+ sh_error("%d: %s", f, strerror(err));
+}
+
+
+/*
+ * Handle here documents. Normally we fork off a process to write the
+ * data to a pipe. If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+STATIC int
+openhere(union node *redir)
+{
+ char *p;
+ int pip[2];
+ size_t len = 0;
+
+ if (pipe(pip) < 0)
+ sh_error("Pipe call failed");
+
+ p = redir->nhere.doc->narg.text;
+ if (redir->type == NXHERE) {
+ expandarg(redir->nhere.doc, NULL, EXP_QUOTED);
+ p = stackblock();
+ }
+
+ len = strlen(p);
+ if (len <= PIPESIZE) {
+ xwrite(pip[1], p, len);
+ goto out;
+ }
+
+ if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+ close(pip[0]);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_IGN);
+#endif
+ signal(SIGPIPE, SIG_DFL);
+ xwrite(pip[1], p, len);
+ _exit(0);
+ }
+out:
+ close(pip[1]);
+ return pip[0];
+}
+
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(int drop)
+{
+ struct redirtab *rp;
+ int i;
+
+ INTOFF;
+ rp = redirlist;
+ for (i = 0 ; i < 10 ; i++) {
+ switch (rp->renamed[i]) {
+ case CLOSED:
+ if (!drop)
+ close(i);
+ break;
+ case EMPTY:
+ case REALLY_CLOSED:
+ break;
+ default:
+ if (!drop)
+ dup2(rp->renamed[i], i);
+ close(rp->renamed[i]);
+ break;
+ }
+ }
+ redirlist = rp->next;
+ ckfree(rp);
+ INTON;
+}
+
+/*
+ * Undo all redirections. Called on error or interrupt.
+ */
+
+#ifdef mkinit
+
+INCLUDE "redir.h"
+
+RESET {
+ /*
+ * Discard all saved file descriptors.
+ */
+ unwindredir(0);
+}
+
+#endif
+
+
+
+/*
+ * Move a file descriptor to > 10. Invokes sh_error on error unless
+ * the original file dscriptor is not open.
+ */
+
+int
+savefd(int from, int ofd)
+{
+ int newfd;
+ int err;
+
+ newfd = fcntl(from, F_DUPFD, 10);
+ err = newfd < 0 ? errno : 0;
+ if (err != EBADF) {
+ close(ofd);
+ if (err)
+ sh_error("%d: %s", from, strerror(err));
+ else
+ fcntl(newfd, F_SETFD, FD_CLOEXEC);
+ }
+
+ return newfd;
+}
+
+
+int
+redirectsafe(union node *redir, int flags)
+{
+ int err;
+ volatile int saveint;
+ struct jmploc *volatile savehandler = handler;
+ struct jmploc jmploc;
+
+ SAVEINT(saveint);
+ if (!(err = setjmp(jmploc.loc) * 2)) {
+ handler = &jmploc;
+ redirect(redir, flags);
+ }
+ handler = savehandler;
+ if (err && exception != EXERROR)
+ longjmp(handler->loc, 1);
+ RESTOREINT(saveint);
+ return err;
+}
+
+
+void unwindredir(struct redirtab *stop)
+{
+ while (redirlist != stop)
+ popredir(0);
+}
+
+
+struct redirtab *pushredir(union node *redir)
+{
+ struct redirtab *sv;
+ struct redirtab *q;
+ int i;
+
+ q = redirlist;
+ if (!redir)
+ goto out;
+
+ sv = ckmalloc(sizeof (struct redirtab));
+ sv->next = q;
+ redirlist = sv;
+ for (i = 0; i < 10; i++)
+ sv->renamed[i] = EMPTY;
+
+out:
+ return q;
+}
diff --git a/usr/dash/redir.h b/usr/dash/redir.h
new file mode 100644
index 0000000..8e56995
--- /dev/null
+++ b/usr/dash/redir.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)redir.h 8.2 (Berkeley) 5/4/95
+ */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01 /* save previous values of file descriptors */
+#ifdef notyet
+#define REDIR_BACKQ 02 /* save the command output in memory */
+#endif
+#define REDIR_SAVEFD2 03 /* set preverrout */
+
+struct redirtab;
+union node;
+void redirect(union node *, int);
+void popredir(int);
+void clearredir(void);
+int savefd(int, int);
+int redirectsafe(union node *, int);
+void unwindredir(struct redirtab *stop);
+struct redirtab *pushredir(union node *redir);
+
diff --git a/usr/dash/sh.1 b/usr/dash/sh.1
new file mode 100644
index 0000000..ff5881a
--- /dev/null
+++ b/usr/dash/sh.1
@@ -0,0 +1,2332 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1997-2005
+.\" Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sh.1 8.6 (Berkeley) 5/4/95
+.\"
+.Dd January 19, 2003
+.Os
+.Dt SH 1
+.Sh NAME
+.Nm sh
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar command_file Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl c
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Ar command_string
+.Op Ar command_name Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl s
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar argument ...
+.Ek
+.Sh DESCRIPTION
+.Nm
+is the standard command interpreter for the system.
+The current version of
+.Nm
+is in the process of being changed to conform with the
+.Tn POSIX
+1003.2 and 1003.2a specifications for the shell.
+This version has many
+features which make it appear similar in some respects to the Korn shell,
+but it is not a Korn shell clone (see
+.Xr ksh 1 ) .
+Only features designated by
+.Tn POSIX ,
+plus a few Berkeley extensions, are being incorporated into this shell.
+We expect
+.Tn POSIX
+conformance by the time 4.4 BSD is released.
+This man page is not intended
+to be a tutorial or a complete specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from either a file or the
+terminal, interprets them, and generally executes other commands.
+It is the program that is running when a user logs into the system
+(although a user can select a different shell with the
+.Xr chsh 1
+command).
+The shell implements a language that has flow control
+constructs, a macro facility that provides a variety of features in
+addition to data storage, along with built in history and line editing
+capabilities.
+It incorporates many features to aid interactive use and
+has the advantage that the interpretative language is common to both
+interactive and non-interactive use (shell scripts).
+That is, commands
+can be typed directly to the running shell or can be put into a file and
+the file can be executed directly by the shell.
+.Ss Invocation
+If no args are present and if the standard input of the shell
+is connected to a terminal (or if the
+.Fl i
+flag is set),
+and the
+.Fl c
+option is not present, the shell is considered an interactive shell.
+An interactive shell generally prompts before each command and handles
+programming and command errors differently (as described below).
+When first starting,
+the shell inspects argument 0, and if it begins with a dash
+.Sq - ,
+the shell is also considered
+a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and
+.Pa .profile
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to an interactive shell, or is set in the
+.Pa .profile
+of a login shell, the shell next reads
+commands from the file named in
+.Ev ENV .
+Therefore, a user should place commands that are to be executed only at
+login time in the
+.Pa .profile
+file, and commands that are executed for every interactive shell inside the
+.Ev ENV
+file.
+To set the
+.Ev ENV
+variable to some file, place the following line in your
+.Pa .profile
+of your home directory
+.Pp
+.Dl ENV=$HOME/.shinit; export ENV
+.Pp
+substituting for
+.Dq .shinit
+any filename you wish.
+.Pp
+If command line arguments besides the options have been specified, then
+the shell treats the first argument as the name of a file from which to
+read commands (a shell script), and the remaining arguments are set as the
+positional parameters of the shell ($1, $2, etc).
+Otherwise, the shell
+reads commands from its standard input.
+.Ss Argument List Processing
+All of the single letter options have a corresponding name that can be
+used as an argument to the
+.Fl o
+option.
+The set
+.Fl o
+name is provided next to the single letter option in
+the description below.
+Specifying a dash
+.Dq -
+turns the option on, while using a plus
+.Dq +
+disables the option.
+The following options can be set from the command line or
+with the
+.Ic set
+builtin (described later).
+.Bl -tag -width aaaallexportfoo -offset indent
+.It Fl a Em allexport
+Export all variables assigned to.
+.It Fl c
+Read commands from the
+.Ar command_string
+operand instead of from the standard input.
+Special parameter 0 will be set from the
+.Ar command_name
+operand and the positional parameters ($1, $2, etc.)
+set from the remaining argument operands.
+.It Fl C Em noclobber
+Don't overwrite existing files with
+.Dq \*[Gt] .
+.It Fl e Em errexit
+If not interactive, exit immediately if any untested command fails.
+The exit status of a command is considered to be
+explicitly tested if the command is used to control an
+.Ic if ,
+.Ic elif ,
+.Ic while ,
+or
+.Ic until ;
+or if the command is the left hand operand of an
+.Dq &&
+or
+.Dq ||
+operator.
+.It Fl f Em noglob
+Disable pathname expansion.
+.It Fl n Em noexec
+If not interactive, read commands but do not execute them.
+This is useful for checking the syntax of shell scripts.
+.It Fl u Em nounset
+Write a message to standard error when attempting to expand a variable
+that is not set, and if the shell is not interactive, exit immediately.
+.It Fl v Em verbose
+The shell writes its input to standard error as it is read.
+Useful for debugging.
+.It Fl x Em xtrace
+Write each command to standard error (preceded by a
+.Sq +\ )
+before it is executed.
+Useful for debugging.
+.It Fl I Em ignoreeof
+Ignore EOF's from input when interactive.
+.It Fl i Em interactive
+Force the shell to behave interactively.
+.It Fl m Em monitor
+Turn on job control (set automatically when interactive).
+.It Fl s Em stdin
+Read commands from standard input (set automatically if no file arguments
+are present).
+This option has no effect when set after the shell has
+already started running (i.e. with
+.Ic set ) .
+.It Fl V Em vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+.It Fl E Em emacs
+Enable the built-in
+.Xr emacs 1
+command line editor (disables
+.Fl V
+if it has been set).
+.It Fl b Em notify
+Enable asynchronous notification of background job completion.
+(UNIMPLEMENTED for 4.4alpha)
+.El
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks it up into
+words at whitespace (blanks and tabs), and at certain sequences of
+characters that are special to the shell called
+.Dq operators .
+There are two types of operators: control operators and redirection
+operators (their meaning is discussed later).
+Following is a list of operators:
+.Bl -ohang -offset indent
+.It "Control operators:"
+.Dl & && \&( \&) \&; ;; | || \*[Lt]newline\*[Gt]
+.It "Redirection operators:"
+.Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]& \*[Gt]& \*[Lt]\*[Lt]- \*[Lt]\*[Gt]
+.El
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters or
+words to the shell, such as operators, whitespace, or keywords.
+There are three types of quoting: matched single quotes,
+matched double quotes, and backslash.
+.Ss Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of
+.Aq newline .
+A backslash preceding a
+.Aq newline
+is treated as a line continuation.
+.Ss Single Quotes
+Enclosing characters in single quotes preserves the literal meaning of all
+the characters (except single quotes, making it impossible to put
+single-quotes in a single-quoted string).
+.Ss Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollarsign
+.Pq $ ,
+backquote
+.Pq ` ,
+and backslash
+.Pq \e .
+The backslash inside double quotes is historically weird, and serves to
+quote only the following characters:
+.Dl $ ` \*q \e \*[Lt]newline\*[Gt] .
+Otherwise it remains literal.
+.Ss Reserved Words
+Reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are reserved words:
+.Bl -column while while while while while -offset indent
+.It ! Ta elif Ta fi Ta while Ta case
+.It else Ta for Ta then Ta { Ta }
+.It do Ta done Ta until Ta if Ta esac
+.El
+.Pp
+Their meaning is discussed later.
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Xr alias 1
+builtin command.
+Whenever a reserved word may occur (see above),
+and after checking for reserved words, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq lf
+with the value
+.Dq "ls -F" ,
+then the input:
+.Pp
+.Dl lf foobar Aq return
+.Pp
+would become
+.Pp
+.Dl ls -F foobar Aq return
+.Pp
+Aliases provide a convenient way for naive users to create shorthands for
+commands without having to learn how to create functions with arguments.
+They can also be used to create lexically obscure code.
+This use is discouraged.
+.Ss Commands
+The shell interprets the words it reads according to a language, the
+specification of which is outside the scope of this man page (refer to the
+BNF in the
+.Tn POSIX
+1003.2 document).
+Essentially though, a line is read and if the first
+word of the line (or after a control operator) is not a reserved word,
+then the shell has recognized a simple command.
+Otherwise, a complex
+command or some other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum -offset indent
+.It
+Leading words of the form
+.Dq name=value
+are stripped off and assigned to the environment of the simple command.
+Redirection operators and their arguments (as described below) are
+stripped off and saved for processing.
+.It
+The remaining words are expanded as described in
+the section called
+.Dq Expansions ,
+and the first remaining word is considered the command name and the
+command is located.
+The remaining words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq name=value
+variable assignments recognized in item 1 affect the current shell.
+.It
+Redirections are performed as described in the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input or sends
+its output.
+In general, redirections open, close, or duplicate an
+existing reference to a file.
+The overall format used for redirection is:
+.Pp
+.Dl [n] Va redir-op Ar file
+.Pp
+where
+.Va redir-op
+is one of the redirection operators mentioned previously.
+Following is a list of the possible redirections.
+The
+.Bq n
+is an optional number, as in
+.Sq 3
+(not
+.Sq Bq 3 ,
+that refers to a file descriptor.
+.Bl -tag -width aaabsfiles -offset indent
+.It [n] Ns \*[Gt] file
+Redirect standard output (or n) to file.
+.It [n] Ns \*[Gt]| file
+Same, but override the
+.Fl C
+option.
+.It [n] Ns \*[Gt]\*[Gt] file
+Append standard output (or n) to file.
+.It [n] Ns \*[Lt] file
+Redirect standard input (or n) from file.
+.It [n1] Ns \*[Lt]& Ns n2
+Duplicate standard input (or n1) from file descriptor n2.
+.It [n] Ns \*[Lt]&-
+Close standard input (or n).
+.It [n1] Ns \*[Gt]& Ns n2
+Duplicate standard output (or n1) to n2.
+.It [n] Ns \*[Gt]&-
+Close standard output (or n).
+.It [n] Ns \*[Lt]\*[Gt] file
+Open file for reading and writing on standard input (or n).
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bl -item -offset indent
+.It
+.Li [n]\*[Lt]\*[Lt] delimiter
+.Dl here-doc-text ...
+.Li delimiter
+.El
+.Pp
+All the text on successive lines up to the delimiter is saved away and
+made available to the command on standard input, or file descriptor n if
+it is specified.
+If the delimiter as specified on the initial line is
+quoted, then the here-doc-text is treated literally, otherwise the text is
+subjected to parameter expansion, command substitution, and arithmetic
+expansion (as described in the section on
+.Dq Expansions ) .
+If the operator is
+.Dq \*[Lt]\*[Lt]-
+instead of
+.Dq \*[Lt]\*[Lt] ,
+then leading tabs in the here-doc-text are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions, builtin commands, and
+normal programs -- and the command is searched for (by name) in that order.
+They each are executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional parameters
+(except $0, which remains unchanged) are set to the arguments of the shell
+function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the function name) are
+made local to the function and are set to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell builtins are executed internally to the shell, without spawning a
+new process.
+.Pp
+Otherwise, if the command name doesn't match a function or builtin, the
+command is searched for as a normal program in the file system (as
+described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file (i.e., if it does
+not begin with the "magic number" whose
+.Tn ASCII
+representation is "#!", so
+.Xr execve 2
+returns
+.Er ENOEXEC
+then) the shell will interpret the program in a subshell.
+The child shell will reinitialize itself in this case,
+so that the effect will be as if a
+new shell had been invoked to handle the ad-hoc shell script, except that
+the location of hashed commands located in the parent shell will be
+remembered by the child.
+.Pp
+Note that previous versions of this document and the source code itself
+misleadingly and sporadically refer to a shell script without a magic
+number as a "shell procedure".
+.Ss Path Search
+When locating a command, the shell first looks to see if it has a shell
+function by that name.
+Then it looks for a builtin command by that name.
+If a builtin command is not found, one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without performing
+any searches.
+.It
+The shell searches each entry in
+.Ev PATH
+in turn for the command.
+The value of the
+.Ev PATH
+variable should be a series of entries separated by colons.
+Each entry consists of a directory name.
+The current directory may be indicated
+implicitly by an empty directory name, or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behaviour
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the builtin commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command consists entirely of variable assignments then the
+exit status of the command is that of the last command substitution
+if any, otherwise 0.
+.Ss Complex Commands
+Complex commands are combinations of simple commands with control
+operators or reserved words, together creating a larger complex command.
+More generally, a command is one of the following:
+.Bl -bullet
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is that of the last
+simple command executed by the command.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator |.
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.Dl [!] command1 [ | command2 ...]
+.Pp
+The standard output of command1 is connected to the standard input of
+command2.
+The standard input, standard output, or both of a command is
+considered to be assigned by the pipeline before any redirection specified
+by redirection operators that are part of the command.
+.Pp
+If the pipeline is not in the background (discussed later), the shell
+waits for all commands to complete.
+.Pp
+If the reserved word ! does not precede the pipeline, the exit status is
+the exit status of the last command specified in the pipeline.
+Otherwise, the exit status is the logical NOT of the exit status of the
+last command.
+That is, if the last command returns zero, the exit status
+is 1; if the last command returns greater than zero, the exit status is
+zero.
+.Pp
+Because pipeline assignment of standard input or standard output or both
+takes place before redirection, it can be modified by redirection.
+For example:
+.Pp
+.Dl $ command1 2\*[Gt]&1 | command2
+.Pp
+sends both the standard output and standard error of command1
+to the standard input of command2.
+.Pp
+A ; or
+.Aq newline
+terminator causes the preceding AND-OR-list (described
+next) to be executed sequentially; a & causes asynchronous execution of
+the preceding AND-OR-list.
+.Pp
+Note that unlike some other shells, each process in the pipeline is a
+child of the invoking shell (unless it is a shell builtin, in which case
+it executes in the current shell -- but any effect it has on the
+environment is wiped).
+.Ss Background Commands -- &
+If a command is terminated by the control operator ampersand (&), the
+shell executes the command asynchronously -- that is, the shell does not
+wait for the command to finish before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.Dl command1 & [command2 & ...]
+.Pp
+If the shell is not interactive, the standard input of an asynchronous
+command is set to
+.Pa /dev/null .
+.Ss Lists -- Generally Speaking
+A list is a sequence of zero or more commands separated by newlines,
+semicolons, or ampersands, and optionally terminated by one of these three
+characters.
+The commands in a list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceed onto the next command; otherwise it waits
+for the command to terminate before proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq &&
+and
+.Dq ||
+are AND-OR list operators.
+.Dq &&
+executes the first command, and then executes the second command iff the
+exit status of the first command is zero.
+.Dq ||
+is similar, but executes the second command iff the exit status of the first
+command is nonzero.
+.Dq &&
+and
+.Dq ||
+both have the same priority.
+.Ss Flow-Control Constructs -- if, while, for, case
+The syntax of the if command is
+.Bd -literal -offset indent
+if list
+then list
+[ elif list
+then list ] ...
+[ else list ]
+fi
+.Ed
+.Pp
+The syntax of the while command is
+.Bd -literal -offset indent
+while list
+do list
+done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The until command is similar, but has the word
+until in place of while, which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The syntax of the for command is
+.Bd -literal -offset indent
+for variable in word ...
+do list
+done
+.Ed
+.Pp
+The words are expanded, and then the list is executed repeatedly with the
+variable set to each word in turn.
+do and done may be replaced with
+.Dq {
+and
+.Dq } .
+.Pp
+The syntax of the break and continue command is
+.Bd -literal -offset indent
+break [ num ]
+continue [ num ]
+.Ed
+.Pp
+Break terminates the num innermost for or while loops.
+Continue continues with the next iteration of the innermost loop.
+These are implemented as builtin commands.
+.Pp
+The syntax of the case command is
+.Bd -literal -offset indent
+case word in
+pattern) list ;;
+\&...
+esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns (see
+.Sx Shell Patterns
+described later), separated by
+.Dq \*(Ba
+characters.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.Dl (list)
+.Pp
+or
+.Pp
+.Dl { list; }
+.Pp
+The first of these executes the commands in a subshell.
+Builtin commands grouped into a (list) will not affect the current shell.
+The second form does not fork another shell so is slightly more efficient.
+Grouping commands together this way allows you to redirect
+their output as though they were one program:
+.Pp
+.Bd -literal -offset indent
+{ printf \*q hello \*q ; printf \*q world\\n" ; } \*[Gt] greeting
+.Ed
+.Pp
+Note that
+.Dq }
+must follow a control operator (here,
+.Dq \&; )
+so that it is recognized as a reserved word and not as another command argument.
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.Dl name ( ) command
+.Pp
+A function definition is an executable statement; when executed it
+installs a function named name and returns an exit status of zero.
+The command is normally a list enclosed between
+.Dq {
+and
+.Dq } .
+.Pp
+Variables may be declared to be local to a function by using a local
+command.
+This should appear as the first statement of a function, and the syntax is
+.Pp
+.Dl local [ variable | - ] ...
+.Pp
+Local is implemented as a builtin command.
+.Pp
+When a variable is made local, it inherits the initial value and exported
+and readonly flags from the variable with the same name in the surrounding
+scope, if there is one.
+Otherwise, the variable is initially unset.
+The shell uses dynamic scoping, so that if you make the variable x local to
+function f, which then calls function g, references to the variable x made
+inside g will refer to the variable x declared inside f, not to the global
+variable named x.
+.Pp
+The only special parameter that can be made local is
+.Dq - .
+Making
+.Dq -
+local any shell options that are changed via the set command inside the
+function to be restored to their original values when the function
+returns.
+.Pp
+The syntax of the return command is
+.Pp
+.Dl return [ exitstatus ]
+.Pp
+It terminates the currently executing function.
+Return is implemented as a builtin command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter denoted by a name is called a variable.
+When starting up, the shell turns all the environment
+variables into shell variables.
+New variables can be set using the form
+.Pp
+.Dl name=value
+.Pp
+Variables set by the user must have a name consisting solely of
+alphabetics, numerics, and underscores - the first of which must not be
+numeric.
+A parameter can also be denoted by a number or a special
+character as explained below.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number (n \*[Gt] 0).
+The shell sets these initially to the values of its command line arguments
+that follow the name of the shell script.
+The
+.Ic set
+builtin can also be used to set or reset them.
+.Ss Special Parameters
+A special parameter is a parameter denoted by one of the following special
+characters.
+The value of the parameter is listed next to its character.
+.Bl -tag -width thinhyphena
+.It *
+Expands to the positional parameters, starting from one.
+When the
+expansion occurs within a double-quoted string it expands to a single
+field with the value of each parameter separated by the first character of
+the
+.Ev IFS
+variable, or by a
+.Aq space
+if
+.Ev IFS
+is unset.
+.It @
+Expands to the positional parameters, starting from one.
+When the expansion occurs within double-quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of @ generates zero arguments, even when @ is
+double-quoted.
+What this basically means, for example, is
+if $1 is
+.Dq abc
+and $2 is
+.Dq def ghi ,
+then
+.Qq $@
+expands to
+the two arguments:
+.Pp
+.Sm off
+.Dl \*q abc \*q \ \*q def\ ghi \*q
+.Sm on
+.It #
+Expands to the number of positional parameters.
+.It ?
+Expands to the exit status of the most recent pipeline.
+.It - (Hyphen.)
+Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the set builtin command, or implicitly
+by the shell.
+.It $
+Expands to the process ID of the invoked shell.
+A subshell retains the same value of $ as its parent.
+.It !
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a pipeline, the process ID is that of the last command in the pipeline.
+.It 0 (Zero.)
+Expands to the name of the shell or shell script.
+.El
+.Ss Word Expansions
+This clause describes the various expansions that are performed on words.
+Not all expansions are performed on every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions, arithmetic
+expansions, and quote removals that occur within a single word expand to a
+single field.
+It is only field splitting or pathname expansion that can
+create multiple fields from a single word.
+The single exception to this
+rule is the expansion of the special parameter @ within double-quotes, as
+was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields
+generated by step (1) unless the
+.Ev IFS
+variable is null.
+.It
+Pathname Expansion (unless set
+.Fl f
+is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The $ character is used to introduce parameter expansion, command
+substitution, or arithmetic evaluation.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character (~) is
+subjected to tilde expansion.
+All the characters up to
+a slash (/) or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.Dl ${expression}
+.Pp
+where expression consists of all characters until the matching
+.Dq } .
+Any
+.Dq }
+escaped by a backslash or within a quoted string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Dq } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.Dl ${parameter}
+.Pp
+The value, if any, of parameter is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double-quotes:
+.Bl -enum
+.It
+Pathname expansion is not performed on the results of the expansion.
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of @.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter:-word}
+Use Default Values.
+If parameter is unset or null, the expansion of word
+is substituted; otherwise, the value of parameter is substituted.
+.It ${parameter:=word}
+Assign Default Values.
+If parameter is unset or null, the expansion of
+word is assigned to parameter.
+In all cases, the final value of parameter is substituted.
+Only variables, not positional parameters or special
+parameters, can be assigned in this way.
+.It ${parameter:?[word]}
+Indicate Error if Null or Unset.
+If parameter is unset or null, the
+expansion of word (or a message indicating it is unset if word is omitted)
+is written to standard error and the shell exits with a nonzero exit status.
+Otherwise, the value of parameter is substituted.
+An interactive shell need not exit.
+.It ${parameter:+word}
+Use Alternative Value.
+If parameter is unset or null, null is
+substituted; otherwise, the expansion of word is substituted.
+.El
+.Pp
+In the parameter expansions shown previously, use of the colon in the
+format results in a test for a parameter that is unset or null; omission
+of the colon results in a test for a parameter that is only unset.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${#parameter}
+String Length.
+The length in characters of the value of parameter.
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation (see
+.Sx Shell Patterns ) ,
+rather than regular expression notation, is used to evaluate the patterns.
+If parameter is * or @, the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double-quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter%word}
+Remove Smallest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the suffix matched by the pattern deleted.
+.It ${parameter%%word}
+Remove Largest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the suffix matched by the pattern deleted.
+.It ${parameter#word}
+Remove Smallest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the prefix matched by the pattern deleted.
+.It ${parameter##word}
+Remove Largest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when the command is enclosed as follows:
+.Pp
+.Dl $(command)
+.Pp
+or
+.Po
+.Dq backquoted
+version
+.Pc :
+.Pp
+.Dl `command`
+.Pp
+The shell expands the command substitution by executing command in a
+subshell environment and replacing the command substitution with the
+standard output of the command, removing sequences of one or more
+.Ao newline Ac Ns s
+at the end of the substitution.
+(Embedded
+.Ao newline Ac Ns s
+before
+the end of the output are not removed; however, during field splitting,
+they may be translated into
+.Ao space Ac Ns s ,
+depending on the value of
+.Ev IFS
+and quoting that is in effect.)
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.Dl $((expression))
+.Pp
+The expression is treated as if it were in double-quotes, except
+that a double-quote inside the expression is not treated specially.
+The shell expands all tokens in the expression for parameter expansion,
+command substitution, and quote removal.
+.Pp
+Next, the shell treats this as an arithmetic expression and
+substitutes the value of the expression.
+.Ss White Space Splitting (Field Splitting)
+After parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double-quotes for
+field splitting and multiple fields can result.
+.Pp
+The shell treats each character of the
+.Ev IFS
+as a delimiter and uses the delimiters to split the results of parameter
+expansion and command substitution into fields.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+flag is set, file name generation is performed after word splitting is
+complete.
+Each word is viewed as a series of patterns, separated by slashes.
+The process of expansion replaces the word with the names of all
+existing files whose names can be formed by replacing each pattern with a
+string that matches the specified pattern.
+There are two restrictions on
+this: first, a pattern cannot match a string containing a slash, and
+second, a pattern cannot match a string starting with a period unless the
+first character of the pattern is a period.
+The next section describes the
+patterns used for both Pathname Expansion and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Dq \&! ,
+.Dq * ,
+.Dq \&? ,
+and
+.Dq \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed
+and the dollar sign or back quotes are not double quoted,
+the value of the variable or the output of
+the command is scanned for these characters and they are turned into
+meta-characters.
+.Pp
+An asterisk
+.Pq Dq *
+matches any string of characters.
+A question mark matches any single character.
+A left bracket
+.Pq Dq \&[
+introduces a character class.
+The end of the character class is indicated by a
+.Pq Dq \&] ;
+if the
+.Dq \&]
+is missing then the
+.Dq \&[
+matches a
+.Dq \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A range of characters may be specified using a minus sign.
+The character class may be complemented
+by making an exclamation point the first character of the character class.
+.Pp
+To include a
+.Dq \&]
+in a character class, make it the first character listed (after the
+.Dq \&! ,
+if any).
+To include a minus sign, make it the first or last character listed.
+.Ss Builtins
+This section lists the builtin commands which are builtin because they
+need to perform some operation that can't be performed by a separate
+process.
+In addition to these, there are several other commands that may
+be builtin for efficiency (e.g.
+.Xr printf 1 ,
+.Xr echo 1 ,
+.Xr test 1 ,
+etc).
+.Bl -tag -width 5n
+.It :
+.It true
+A null command that returns a 0 (true) exit value.
+.It \&. file
+The commands in the specified file are read and executed by the shell.
+.It alias Op Ar name Ns Op Ar "=string ..."
+If
+.Ar name=string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+builtin prints the
+names and values of all defined aliases (see
+.Ic unalias ) .
+.It bg [ Ar job ] ...
+Continue the specified jobs (or the current job if no
+jobs are given) in the background.
+.It Xo command
+.Op Fl p
+.Op Fl v
+.Op Fl V
+.Ar command
+.Op Ar arg ...
+.Xc
+Execute the specified command but ignore shell functions when searching
+for it.
+(This is useful when you
+have a shell function with the same name as a builtin command.)
+.Bl -tag -width 5n
+.It Fl p
+search for command using a
+.Ev PATH
+that guarantees to find all the standard utilities.
+.It Fl V
+Do not execute the command but
+search for the command and print the resolution of the
+command search.
+This is the same as the type builtin.
+.It Fl v
+Do not execute the command but
+search for the command and print the absolute pathname
+of utilities, the name for builtins or the expansion of aliases.
+.El
+.It cd Ar -
+.It Xo cd Op Fl LP
+.Op Ar directory
+.Xc
+Switch to the specified directory (default
+.Ev HOME ) .
+If an entry for
+.Ev CDPATH
+appears in the environment of the
+.Ic cd
+command or the shell variable
+.Ev CDPATH
+is set and the directory name does not begin with a slash, then the
+directories listed in
+.Ev CDPATH
+will be searched for the specified directory.
+The format of
+.Ev CDPATH
+is the same as that of
+.Ev PATH .
+If a single dash is specified as the argument, it will be replaced by the
+value of
+.Ev OLDPWD .
+The
+.Ic cd
+command will print out the name of the
+directory that it actually switched to if this is different from the name
+that the user gave.
+These may be different either because the
+.Ev CDPATH
+mechanism was used or because the argument is a single dash.
+The
+.Fl P
+option causes the physical directory structure to be used, that is, all
+symbolic links are resolved to their respective values. The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo echo Op Fl n
+.Ar args...
+.Xc
+Print the arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output. Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed. This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Ic echo
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three octal digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Pp
+All other backslash sequences elicit undefined behaviour.
+.It eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It exec Op Ar command arg ...
+Unless command is omitted, the shell process is replaced with the
+specified program (which must be a real program, not a shell builtin or
+function).
+Any redirections on the
+.Ic exec
+command are marked as permanent, so that they are not undone when the
+.Ic exec
+command finishes.
+.It exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given it is used as the exit status of the shell; otherwise the
+exit status of the preceding command is used.
+.It export Ar name ...
+.It export Fl p
+The specified names are exported so that they will appear in the
+environment of subsequent commands.
+The only way to un-export a variable is to unset it.
+The shell allows the value of a variable to be set at the
+same time it is exported by writing
+.Pp
+.Dl export name=value
+.Pp
+With no arguments the export command lists the names of all exported variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.It Xo fc Op Fl e Ar editor
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl l
+.Op Fl nr
+.Op Ar first Op Ar last
+.Xc
+.It Xo fc Fl s Op Ar old=new
+.Op Ar first
+.Xc
+The
+.Ic fc
+builtin lists, or edits and re-executes, commands previously entered
+to an interactive shell.
+.Bl -tag -width 5n
+.It Fl e No editor
+Use the editor named by editor to edit the commands.
+The editor string is a command name, subject to search via the
+.Ev PATH
+variable.
+The value in the
+.Ev FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Ev FCEDIT
+is null or unset, the value of the
+.Ev EDITOR
+variable is used.
+If
+.Ev EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking an editor on them.
+The commands are written in the sequence indicated by
+the first and last operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with -l.
+.It Fl r
+Reverse the order of the commands listed (with
+.Fl l )
+or edited (with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It first
+.It last
+Select the commands to list or edit.
+The number of previous commands that
+can be accessed are determined by the value of the
+.Ev HISTSIZE
+variable.
+The value of first or last or both are one of the following:
+.Bl -tag -width 5n
+.It [+]number
+A positive number representing a command number; command numbers can be
+displayed with the
+.Fl l
+option.
+.It Fl number
+A negative decimal number representing the command that was executed
+number of commands previously.
+For example, \-1 is the immediately previous command.
+.El
+.It string
+A string indicating the most recently entered command that begins with
+that string.
+If the old=new operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.Pp
+The following environment variables affect the execution of fc:
+.Bl -tag -width HISTSIZE
+.It Ev FCEDIT
+Name of the editor to use.
+.It Ev HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It fg Op Ar job
+Move the specified job or the current job to the foreground.
+.It getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command, not to be confused with the
+.Em Bell Labs
+-derived
+.Xr getopt 1 .
+.Pp
+The first argument should be a series of letters, each of which may be
+optionally followed by a colon to indicate that the option requires an
+argument.
+The variable specified is set to the parsed option.
+.Pp
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+utility due to its handling of arguments containing whitespace.
+.Pp
+The
+.Ic getopts
+builtin may be used to obtain options and their arguments
+from a list of parameters.
+When invoked,
+.Ic getopts
+places the value of the next option from the option string in the list in
+the shell variable specified by
+.Va var
+and its index in the shell variable
+.Ev OPTIND .
+When the shell is invoked,
+.Ev OPTIND
+is initialized to 1.
+For each option that requires an argument, the
+.Ic getopts
+builtin will place it in the shell variable
+.Ev OPTARG .
+If an option is not allowed for in the
+.Va optstring ,
+then
+.Ev OPTARG
+will be unset.
+.Pp
+.Va optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) .
+If a letter is followed by a colon, the option is expected to have an
+argument which may or may not be separated from it by white space.
+If an option character is not found where expected,
+.Ic getopts
+will set the variable
+.Va var
+to a
+.Dq \&? ;
+.Ic getopts
+will then unset
+.Ev OPTARG
+and write output to standard error.
+By specifying a colon as the first character of
+.Va optstring
+all errors will be ignored.
+.Pp
+A nonzero value is returned when the last option is reached.
+If there are no remaining arguments,
+.Ic getopts
+will set
+.Va var
+to the special option,
+.Dq -- ,
+otherwise, it will set
+.Va var
+to
+.Dq \&? .
+.Pp
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Op a
+and
+.Op b ,
+and the option
+.Op c ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+while getopts abc: f
+do
+ case $f in
+ a | b) flag=$f;;
+ c) carg=$OPTARG;;
+ \\?) echo $USAGE; exit 1;;
+ esac
+done
+shift `expr $OPTIND - 1`
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-acarg file file
+cmd \-a \-c arg file file
+cmd \-carg -a file file
+cmd \-a \-carg \-\- file file
+.Ed
+.It hash Fl rv Ar command ...
+The shell maintains a hash table which remembers the
+locations of commands.
+With no arguments whatsoever,
+the
+.Ic hash
+command prints out the contents of this table.
+Entries which have not been looked at since the last
+.Ic cd
+command are marked with an asterisk; it is possible for these entries
+to be invalid.
+.Pp
+With arguments, the
+.Ic hash
+command removes the specified commands from the hash table (unless
+they are functions) and then locates them.
+With the
+.Fl v
+option, hash prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the hash command to delete all the entries in the hash table
+except for functions.
+.It pwd Op Fl LP
+builtin command remembers what the current directory
+is rather than recomputing it each time.
+This makes it faster.
+However, if the current directory is renamed, the builtin version of
+.Ic pwd
+will continue to print the old name for the directory.
+The
+.Fl P
+option causes the physical value of the current working directory to be shown,
+that is, all symbolic links are resolved to their respective values. The
+.Fl L
+option turns off the effect of any preceding
+.Fl P
+options.
+.It Xo read Op Fl p Ar prompt
+.Op Fl r
+.Ar variable
+.Op Ar ...
+.Xc
+The prompt is printed if the
+.Fl p
+option is specified and the standard input is a terminal.
+Then a line is read from the standard input.
+The trailing newline is deleted from the
+line and the line is split as described in the section on word splitting
+above, and the pieces are assigned to the variables in order.
+At least one variable must be specified.
+If there are more pieces than variables, the remaining pieces
+(along with the characters in
+.Ev IFS
+that separated them) are assigned to the last variable.
+If there are more variables than pieces,
+the remaining variables are assigned the null string.
+The
+.Ic read
+builtin will indicate success unless EOF is encountered on input, in
+which case failure is returned.
+.Pp
+By default, unless the
+.Fl r
+option is specified, the backslash
+.Dq \e
+acts as an escape character, causing the following character to be treated
+literally.
+If a backslash is followed by a newline, the backslash and the
+newline will be deleted.
+.It readonly Ar name ...
+.It readonly Fl p
+The specified names are marked as read only, so that they cannot be
+subsequently modified or unset.
+The shell allows the value of a variable
+to be set at the same time it is marked read only by writing
+.Pp
+.Dl readonly name=value
+.Pp
+With no arguments the readonly command lists the names of all read only
+variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.Pp
+.It Xo printf Ar format
+.Op Ar arguments ...
+.Xc
+.Ic printf
+formats and prints its arguments, after the first, under control
+of the
+.Ar format .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm b ,
+.Cm c
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+.Tn ASCII
+code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in
+.St -ansiC .
+The characters and their meanings are as follows:
+.Bl -tag -width Ds -offset indent
+.It Cm \ea
+Write a \*[Lt]bell\*[Gt] character.
+.It Cm \eb
+Write a \*[Lt]backspace\*[Gt] character.
+.It Cm \ef
+Write a \*[Lt]form-feed\*[Gt] character.
+.It Cm \en
+Write a \*[Lt]new-line\*[Gt] character.
+.It Cm \er
+Write a \*[Lt]carriage return\*[Gt] character.
+.It Cm \et
+Write a \*[Lt]tab\*[Gt] character.
+.It Cm \ev
+Write a \*[Lt]vertical tab\*[Gt] character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternative form''.
+For
+.Cm b ,
+.Cm c ,
+.Cm d ,
+and
+.Cm s
+formats, this option has no effect.
+For the
+.Cm o
+format the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm e ,
+.Cm E ,
+.Cm f ,
+.Cm g ,
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be.
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer characters than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision :
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of characters to be printed
+from a string
+.Sm off
+.Pf ( Cm b
+.Sm on
+and
+.Cm s
+formats); if the digit string is missing, the precision is treated
+as zero;
+.It Format :
+A character which indicates the type of format to use (one of
+.Cm diouxXfwEgGbcs ) .
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm f
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]ddd Cm \&. No ddd
+.Sm on
+where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Sm off
+.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+An upper-case E is used for an `E' format.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm b
+Characters from the string
+.Ar argument
+are printed with backslash-escape sequences expanded.
+.br
+The following additional backslash-escape sequences are supported:
+.Bl -tag -width Ds
+.It Cm \ec
+Causes
+.Nm
+to ignore any remaining characters in the string operand containing it,
+any remaining string operands, and any additional characters in
+the format operand.
+.It Cm \e0 Ns Ar num
+Write an 8\-bit character whose
+.Tn ASCII
+value is the 1\-, 2\-, or 3\-digit
+octal number
+.Ar num .
+.El
+.It Cm c
+The first character of
+.Ar argument
+is printed.
+.It Cm s
+Characters from the string
+.Ar argument
+are printed until the end is reached or until the number of characters
+indicated by the precision specification is reached; if the
+precision is omitted, all characters in the string are printed.
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.It Xo set
+.Oo {
+.Fl options | Cm +options | Cm -- }
+.Oc Ar arg ...
+.Xc
+The
+.Ic set
+command performs three different functions.
+.Pp
+With no arguments, it lists the values of all shell variables.
+.Pp
+If options are given, it sets the specified option
+flags, or clears them as described in the section called
+.Sx Argument List Processing .
+.Pp
+The third use of the set command is to set the values of the shell's
+positional parameters to the specified args.
+To change the positional
+parameters without changing any options, use
+.Dq --
+as the first argument to set.
+If no args are present, the set command
+will clear all the positional parameters (equivalent to executing
+.Dq shift $# . )
+.It shift Op Ar n
+Shift the positional parameters n times.
+A
+.Ic shift
+sets the value of
+.Va $1
+to the value of
+.Va $2 ,
+the value of
+.Va $2
+to the value of
+.Va $3 ,
+and so on, decreasing
+the value of
+.Va $#
+by one.
+If n is greater than the number of positional parameters,
+.Ic shift
+will issue an error message, and exit with return status 2.
+.It test Ar expression
+.It \&[ Ar expression Cm ]
+The
+.Ic test
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression, test also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Ic test
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Po Tn FIFO Pc .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl h
+instead.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar \&s\&1 Cm \&= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are identical.
+.It Ar \&s\&1 Cm \&!= Ar \&s\&2
+True if the strings
+.Ar \&s\&1
+and
+.Ar \&s\&2
+are not identical.
+.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes before
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2
+True if string
+.Ar \&s\&1
+comes after
+.Ar \&s\&2
+based on the ASCII value of their characters.
+.It Ar \&n\&1 Fl \&eq Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are algebraically
+equal.
+.It Ar \&n\&1 Fl \&ne Ar \&n\&2
+True if the integers
+.Ar \&n\&1
+and
+.Ar \&n\&2
+are not
+algebraically equal.
+.It Ar \&n\&1 Fl \&gt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&ge Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically
+greater than or equal to the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&lt Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than the integer
+.Ar \&n\&2 .
+.It Ar \&n\&1 Fl \&le Ar \&n\&2
+True if the integer
+.Ar \&n\&1
+is algebraically less
+than or equal to the integer
+.Ar \&n\&2 .
+.El
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ns Ar expression Ns Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.It times
+Print the accumulated user and system times for the shell and for processes
+run from the shell. The return status is 0.
+.It Xo trap
+.Op Ar action Ar signal ...
+.Xc
+Cause the shell to parse and execute action when any of the specified
+signals are received.
+The signals are specified by signal number or as the name of the signal.
+If
+.Ar signal
+is
+.Li 0 ,
+the action is executed when the shell exits.
+.Ar action
+may be null, which cause the specified signals to be ignored.
+With
+.Ar action
+omitted or set to `-' the specified signals are set to their default action.
+When the shell forks off a subshell, it resets trapped (but not ignored)
+signals to the default action.
+The
+.Ic trap
+command has no effect on signals that were
+ignored on entry to the shell.
+.Ic trap
+without any arguments cause it to write a list of signals and their
+associated action to the standard output in a format that is suitable
+as an input to the shell that achieves the same trapping results.
+.Pp
+Examples:
+.Pp
+.Dl trap
+.Pp
+List trapped signals and their corresponding action
+.Pp
+.Dl trap '' INT QUIT tstp 30
+.Pp
+Ignore signals INT QUIT TSTP USR1
+.Pp
+.Dl trap date INT
+.Pp
+Print date upon receiving signal INT
+.It type Op Ar name ...
+Interpret each name as a command and print the resolution of the command
+search.
+Possible resolutions are:
+shell keyword, alias, shell builtin,
+command, tracked alias and not found.
+For aliases the alias expansion is
+printed; for commands and tracked aliases the complete pathname of the
+command is printed.
+.It ulimit Xo
+.Op Fl H \*(Ba Fl S
+.Op Fl a \*(Ba Fl tfdscmlpn Op Ar value
+.Xc
+Inquire about or set the hard or soft limits on processes or set new
+limits.
+The choice between hard limit (which no process is allowed to
+violate, and which may not be raised once it has been lowered) and soft
+limit (which causes processes to be signaled but not necessarily killed,
+and which may be raised) is made with these flags:
+.Bl -tag -width Fl
+.It Fl H
+set or inquire about hard limits
+.It Fl S
+set or inquire about soft limits.
+If neither
+.Fl H
+nor
+.Fl S
+is specified, the soft limit is displayed or both limits are set.
+If both are specified, the last one wins.
+.El
+.Pp
+.Bl -tag -width Fl
+The limit to be interrogated or set, then, is chosen by specifying
+any one of these flags:
+.It Fl a
+show all the current limits
+.It Fl t
+show or set the limit on CPU time (in seconds)
+.It Fl f
+show or set the limit on the largest file that can be created
+(in 512-byte blocks)
+.It Fl d
+show or set the limit on the data segment size of a process (in kilobytes)
+.It Fl s
+show or set the limit on the stack size of a process (in kilobytes)
+.It Fl c
+show or set the limit on the largest core dump size that can be produced
+(in 512-byte blocks)
+.It Fl m
+show or set the limit on the total physical memory that can be
+in use by a process (in kilobytes)
+.It Fl l
+show or set the limit on how much memory a process can lock with
+.Xr mlock 2
+(in kilobytes)
+.It Fl p
+show or set the limit on the number of processes this user can
+have at one time
+.It Fl n
+show or set the limit on the number files a process can have open at once
+.El
+.Pp
+If none of these is specified, it is the limit on file size that is shown
+or set.
+If value is specified, the limit is set to that number; otherwise
+the current limit is displayed.
+.Pp
+Limits of an arbitrary process can be displayed or set using the
+.Xr sysctl 8
+utility.
+.Pp
+.It umask Op Ar mask
+Set the value of umask (see
+.Xr umask 2 )
+to the specified octal value.
+If the argument is omitted, the umask value is printed.
+.It unalias Xo
+.Op Fl a
+.Op Ar name
+.Xc
+If
+.Ar name
+is specified, the shell removes that alias.
+If
+.Fl a
+is specified, all aliases are removed.
+.It unset Xo
+.Op Fl fv
+.Ar name ...
+.Xc
+The specified variables and functions are unset and unexported.
+If
+.Fl f
+or
+.Fl v
+is specified, the corresponding function or variable is unset, respectively.
+If a given name corresponds to both a variable and a function, and no
+options are given, only the variable is unset.
+.It wait Op Ar job
+Wait for the specified job to complete and return the exit status of the
+last process in the job.
+If the argument is omitted, wait for all jobs to
+complete and the return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history (see
+.Ic fc
+in
+.Sx Builtins )
+can be edited using vi-mode command-line editing.
+This mode uses commands, described below,
+similar to a subset of those described in the vi man page.
+The command
+.Ql set -o vi
+enables vi-mode editing and place sh into vi insert mode.
+With vi-mode
+enabled, sh can be switched between insert mode and command mode.
+The editor is not described in full here, but will be in a later document.
+It's similar to vi: typing
+.Aq ESC
+will throw you into command VI command mode.
+Hitting
+.Aq return
+while in command mode will pass the line to the shell.
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will cause the
+shell to exit with a non-zero exit status.
+If the shell is not an
+interactive shell, the execution of the shell file will be aborted.
+Otherwise
+the shell will return the exit status of the last command executed, or
+if the exit builtin is used with a numeric argument, it will return the
+argument.
+.Sh ENVIRONMENT
+.Bl -tag -width MAILCHECK
+.It Ev HOME
+Set automatically by
+.Xr login 1
+from the user's login directory in the password file
+.Pq Xr passwd 4 .
+This environment variable also functions as the default argument for the
+cd builtin.
+.It Ev PATH
+The default search path for executables.
+See the above section
+.Sx Path Search .
+.It Ev CDPATH
+The search path used with the cd builtin.
+.It Ev MAIL
+The name of a mail file, that will be checked for the arrival of new mail.
+Overridden by
+.Ev MAILPATH .
+.It Ev MAILCHECK
+The frequency in seconds that the shell checks for the arrival of mail
+in the files specified by the
+.Ev MAILPATH
+or the
+.Ev MAIL
+file.
+If set to 0, the check will occur at each prompt.
+.It Ev MAILPATH
+A colon
+.Dq \&:
+separated list of file names, for the shell to check for incoming mail.
+This environment setting overrides the
+.Ev MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Ev PS1
+The primary prompt string, which defaults to
+.Dq $ \ ,
+unless you are the superuser, in which case it defaults to
+.Dq # \ .
+.It Ev PS2
+The secondary prompt string, which defaults to
+.Dq \*[Gt] \ .
+.It Ev PS4
+Output before each line when execution trace (set -x) is enabled,
+defaults to
+.Dq + \ .
+.It Ev IFS
+Input Field Separators.
+This is normally set to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline .
+See the
+.Sx White Space Splitting
+section for more details.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by
+children of the shell, and is used in the history editing modes.
+.It Ev HISTSIZE
+The number of lines in the history buffer for the shell.
+.It Ev PWD
+The logical value of the current working directory. This is set by the
+.Ic cd
+command.
+.It Ev OLDPWD
+The previous logical value of the current working directory. This is set by
+the
+.Ic cd
+command.
+.It Ev PPID
+The process ID of the parent process of the shell.
+.El
+.Sh FILES
+.Bl -item -width HOMEprofilexxxx
+.It
+.Pa $HOME/.profile
+.It
+.Pa /etc/profile
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr echo 1 ,
+.Xr getopt 1 ,
+.Xr ksh 1 ,
+.Xr login 1 ,
+.Xr printf 1 ,
+.Xr test 1 ,
+.Xr getopt 3 ,
+.Xr passwd 5 ,
+.\" .Xr profile 4 ,
+.Xr environ 7 ,
+.Xr sysctl 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+It was, however, unmaintainable so we wrote this one.
+.Sh BUGS
+Setuid shell scripts should be avoided at all costs, as they are a
+significant security risk.
+.Pp
+PS1, PS2, and PS4 should be subject to parameter expansion before
+being displayed.
diff --git a/usr/dash/shell.h b/usr/dash/shell.h
new file mode 100644
index 0000000..98edc8b
--- /dev/null
+++ b/usr/dash/shell.h
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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.h 8.2 (Berkeley) 5/4/95
+ */
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ * SHORTNAMES -> 1 if your linker cannot handle long names.
+ * define BSD if you are running 4.2 BSD or later.
+ * define SYSV if you are running under System V.
+ * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
+ * define DEBUG=2 to compile in and turn on debugging.
+ * define DO_SHAREDVFORK to indicate that vfork(2) shares its address
+ * with its parent.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+#include <sys/param.h>
+
+#ifndef JOBS
+#define JOBS 1
+#endif
+#ifndef BSD
+#define BSD 1
+#endif
+
+#ifndef DO_SHAREDVFORK
+#if __NetBSD_Version__ >= 104000000
+#define DO_SHAREDVFORK
+#endif
+#endif
+
+typedef void *pointer;
+#ifndef NULL
+#define NULL (void *)0
+#endif
+#define STATIC static
+#define MKINIT /* empty */
+
+extern char nullstr[1]; /* null string */
+
+
+#ifdef DEBUG
+#define TRACE(param) trace param
+#define TRACEV(param) tracev param
+#else
+#define TRACE(param)
+#define TRACEV(param)
+#endif
+
+#if defined(__GNUC__) && __GNUC__ < 3
+#define va_copy __va_copy
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
+#define likely(x) __builtin_expect(!!(x),1)
+#define unlikely(x) __builtin_expect(!!(x),0)
+
+/*
+ * Hack to calculate maximum length.
+ * (length * 8 - 1) * log10(2) + 1 + 1 + 12
+ * The second 1 is for the minus sign and the 12 is a safety margin.
+ */
+static inline int max_int_length(int bytes)
+{
+ return (bytes * 8 - 1) * 0.30102999566398119521 + 14;
+}
diff --git a/usr/dash/show.c b/usr/dash/show.c
new file mode 100644
index 0000000..4a049e9
--- /dev/null
+++ b/usr/dash/show.c
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "mystring.h"
+#include "show.h"
+#include "options.h"
+
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+ trputs("showtree called\n");
+ shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+ struct nodelist *lp;
+ const char *s;
+
+ if (n == NULL)
+ return;
+
+ indent(ind, pfx, fp);
+ switch(n->type) {
+ case NSEMI:
+ s = "; ";
+ goto binop;
+ case NAND:
+ s = " && ";
+ goto binop;
+ case NOR:
+ s = " || ";
+binop:
+ shtree(n->nbinary.ch1, ind, NULL, fp);
+ /* if (ind < 0) */
+ fputs(s, fp);
+ shtree(n->nbinary.ch2, ind, NULL, fp);
+ break;
+ case NCMD:
+ shcmd(n, fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ case NPIPE:
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ shcmd(lp->n, fp);
+ if (lp->next)
+ fputs(" | ", fp);
+ }
+ if (n->npipe.backgnd)
+ fputs(" &", fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ default:
+ fprintf(fp, "<node type %d>", n->type);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ }
+}
+
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+ union node *np;
+ int first;
+ const char *s;
+ int dftfd;
+
+ first = 1;
+ for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+ if (! first)
+ putchar(' ');
+ sharg(np, fp);
+ first = 0;
+ }
+ for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+ if (! first)
+ putchar(' ');
+ switch (np->nfile.type) {
+ case NTO: s = ">"; dftfd = 1; break;
+ case NCLOBBER: s = ">|"; dftfd = 1; break;
+ case NAPPEND: s = ">>"; dftfd = 1; break;
+ case NTOFD: s = ">&"; dftfd = 1; break;
+ case NFROM: s = "<"; dftfd = 0; break;
+ case NFROMFD: s = "<&"; dftfd = 0; break;
+ case NFROMTO: s = "<>"; dftfd = 0; break;
+ default: s = "*error*"; dftfd = 0; break;
+ }
+ if (np->nfile.fd != dftfd)
+ fprintf(fp, "%d", np->nfile.fd);
+ fputs(s, fp);
+ if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+ fprintf(fp, "%d", np->ndup.dupfd);
+ } else {
+ sharg(np->nfile.fname, fp);
+ }
+ first = 0;
+ }
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+ char *p;
+ struct nodelist *bqlist;
+ int subtype;
+
+ if (arg->type != NARG) {
+ printf("<node type %d>\n", arg->type);
+ abort();
+ }
+ bqlist = arg->narg.backquote;
+ for (p = arg->narg.text ; *p ; p++) {
+ switch ((signed char)*p) {
+ case CTLESC:
+ putc(*++p, fp);
+ break;
+ case CTLVAR:
+ putc('$', fp);
+ putc('{', fp);
+ subtype = *++p;
+ if (subtype == VSLENGTH)
+ putc('#', fp);
+
+ while (*p != '=')
+ putc(*p++, fp);
+
+ if (subtype & VSNUL)
+ putc(':', fp);
+
+ switch (subtype & VSTYPE) {
+ case VSNORMAL:
+ putc('}', fp);
+ break;
+ case VSMINUS:
+ putc('-', fp);
+ break;
+ case VSPLUS:
+ putc('+', fp);
+ break;
+ case VSQUESTION:
+ putc('?', fp);
+ break;
+ case VSASSIGN:
+ putc('=', fp);
+ break;
+ case VSTRIMLEFT:
+ putc('#', fp);
+ break;
+ case VSTRIMLEFTMAX:
+ putc('#', fp);
+ putc('#', fp);
+ break;
+ case VSTRIMRIGHT:
+ putc('%', fp);
+ break;
+ case VSTRIMRIGHTMAX:
+ putc('%', fp);
+ putc('%', fp);
+ break;
+ case VSLENGTH:
+ break;
+ default:
+ printf("<subtype %d>", subtype);
+ }
+ break;
+ case CTLENDVAR:
+ putc('}', fp);
+ break;
+ case CTLBACKQ:
+ putc('$', fp);
+ putc('(', fp);
+ shtree(bqlist->n, -1, NULL, fp);
+ putc(')', fp);
+ break;
+ default:
+ putc(*p, fp);
+ break;
+ }
+ }
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+ int i;
+
+ for (i = 0 ; i < amount ; i++) {
+ if (pfx && i == amount - 1)
+ fputs(pfx, fp);
+ putc('\t', fp);
+ }
+}
+
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+
+void
+trputc(int c)
+{
+ if (debug != 1)
+ return;
+ putc(c, tracefile);
+}
+
+void
+trace(const char *fmt, ...)
+{
+ va_list va;
+
+ if (debug != 1)
+ return;
+ va_start(va, fmt);
+ (void) vfprintf(tracefile, fmt, va);
+ va_end(va);
+}
+
+void
+tracev(const char *fmt, va_list va)
+{
+ if (debug != 1)
+ return;
+ (void) vfprintf(tracefile, fmt, va);
+}
+
+
+void
+trputs(const char *s)
+{
+ if (debug != 1)
+ return;
+ fputs(s, tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+ char *p;
+ char c;
+
+ if (debug != 1)
+ return;
+ putc('"', tracefile);
+ for (p = s ; *p ; p++) {
+ switch ((signed char)*p) {
+ case '\n': c = 'n'; goto backslash;
+ case '\t': c = 't'; goto backslash;
+ case '\r': c = 'r'; goto backslash;
+ case '"': c = '"'; goto backslash;
+ case '\\': c = '\\'; goto backslash;
+ case CTLESC: c = 'e'; goto backslash;
+ case CTLVAR: c = 'v'; goto backslash;
+ case CTLBACKQ: c = 'q'; goto backslash;
+backslash: putc('\\', tracefile);
+ putc(c, tracefile);
+ break;
+ default:
+ if (*p >= ' ' && *p <= '~')
+ putc(*p, tracefile);
+ else {
+ putc('\\', tracefile);
+ putc(*p >> 6 & 03, tracefile);
+ putc(*p >> 3 & 07, tracefile);
+ putc(*p & 07, tracefile);
+ }
+ break;
+ }
+ }
+ putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+ if (debug != 1)
+ return;
+ while (*ap) {
+ trstring(*ap++);
+ if (*ap)
+ putc(' ', tracefile);
+ else
+ putc('\n', tracefile);
+ }
+}
+
+
+void
+opentrace(void)
+{
+ char s[100];
+#ifdef O_APPEND
+ int flags;
+#endif
+
+ if (debug != 1) {
+ if (tracefile)
+ fflush(tracefile);
+ /* leave open because libedit might be using it */
+ return;
+ }
+#ifdef not_this_way
+ {
+ char *p;
+ if ((p = getenv(homestr)) == NULL) {
+ if (geteuid() == 0)
+ p = "/";
+ else
+ p = "/tmp";
+ }
+ scopy(p, s);
+ strcat(s, "/trace");
+ }
+#else
+ scopy("./trace", s);
+#endif /* not_this_way */
+ if (tracefile) {
+#ifndef __KLIBC__
+ if (!freopen(s, "a", tracefile)) {
+#else
+ if (!(!fclose(tracefile) && (tracefile = fopen(s, "a")))) {
+#endif /* __KLIBC__ */
+ fprintf(stderr, "Can't re-open %s\n", s);
+ debug = 0;
+ return;
+ }
+ } else {
+ if ((tracefile = fopen(s, "a")) == NULL) {
+ fprintf(stderr, "Can't open %s\n", s);
+ debug = 0;
+ return;
+ }
+ }
+#ifdef O_APPEND
+ if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+ fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+#endif
+#ifndef __KLIBC__
+ setlinebuf(tracefile);
+#endif /* __KLIBC__ */
+ fputs("\nTracing started.\n", tracefile);
+}
+#endif /* DEBUG */
diff --git a/usr/dash/show.h b/usr/dash/show.h
new file mode 100644
index 0000000..d0ccac7
--- /dev/null
+++ b/usr/dash/show.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)show.h 1.1 (Berkeley) 5/4/95
+ */
+
+#include <stdarg.h>
+
+#ifdef DEBUG
+union node;
+void showtree(union node *);
+void trace(const char *, ...);
+void tracev(const char *, va_list);
+void trargs(char **);
+void trputc(int);
+void trputs(const char *);
+void opentrace(void);
+#endif
diff --git a/usr/dash/system.c b/usr/dash/system.c
new file mode 100644
index 0000000..aa1df8a
--- /dev/null
+++ b/usr/dash/system.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2004
+ * Herbert Xu <herbert@gondor.apana.org.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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HAVE_ISALPHA
+#define isalnum _isalnum
+#define iscntrl _iscntrl
+#define islower _islower
+#define isspace _isspace
+#define isalpha _isalpha
+#define isdigit _isdigit
+#define isprint _isprint
+#define isupper _isupper
+#define isblank _isblank
+#define isgraph _isgraph
+#define ispunct _ispunct
+#define isxdigit _isxdigit
+#include <ctype.h>
+#undef isalnum
+#undef iscntrl
+#undef islower
+#undef isspace
+#undef isalpha
+#undef isdigit
+#undef isprint
+#undef isupper
+#undef isblank
+#undef isgraph
+#undef ispunct
+#undef isxdigit
+#endif
+
+#include <signal.h>
+#include <string.h>
+
+#include "error.h"
+#include "output.h"
+#include "system.h"
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *dest, const void *src, size_t n)
+{
+ return memcpy(dest, src, n) + n;
+}
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *dest, const char *src)
+{
+ size_t len = strlen(src);
+ dest[len] = 0;
+ return mempcpy(dest, src, len);
+}
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *s, int c)
+{
+ char *p = strchr(s, c);
+ if (!p)
+ p = (char *)s + strlen(s);
+ return p;
+}
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int sig)
+{
+ static char buf[19];
+
+ if ((unsigned)sig < NSIG && sys_siglist[sig])
+ return (char *)sys_siglist[sig];
+ fmtstr(buf, sizeof(buf), "Signal %d", sig);
+ return buf;
+}
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*cmp)(const void *, const void *))
+{
+ while (nmemb) {
+ size_t mididx = nmemb / 2;
+ const void *midobj = base + mididx * size;
+ int diff = cmp(key, midobj);
+
+ if (diff == 0)
+ return (void *)midobj;
+
+ if (diff > 0) {
+ base = midobj + size;
+ nmemb -= mididx + 1;
+ } else
+ nmemb = mididx;
+ }
+
+ return 0;
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+long sysconf(int name)
+{
+ sh_error("no sysconf for: %d", name);
+}
+#endif
+
+#ifndef HAVE_ISALPHA
+int isalnum(int c) {
+ return _isalnum(c);
+}
+
+
+int iscntrl(int c) {
+ return _iscntrl(c);
+}
+
+
+int islower(int c) {
+ return _islower(c);
+}
+
+
+int isspace(int c) {
+ return _isspace(c);
+}
+
+
+int isalpha(int c) {
+ return _isalpha(c);
+}
+
+
+int isdigit(int c) {
+ return _isdigit(c);
+}
+
+
+int isprint(int c) {
+ return _isprint(c);
+}
+
+
+int isupper(int c) {
+ return _isupper(c);
+}
+
+
+#if HAVE_DECL_ISBLANK
+int isblank(int c) {
+ return _isblank(c);
+}
+#endif
+
+
+int isgraph(int c) {
+ return _isgraph(c);
+}
+
+
+int ispunct(int c) {
+ return _ispunct(c);
+}
+
+
+int isxdigit(int c) {
+ return _isxdigit(c);
+}
+#endif
+
+#if !HAVE_DECL_ISBLANK
+int isblank(int c) {
+ return c == ' ' || c == '\t';
+}
+#endif
diff --git a/usr/dash/system.h b/usr/dash/system.h
new file mode 100644
index 0000000..c8424f7
--- /dev/null
+++ b/usr/dash/system.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2004
+ * Herbert Xu <herbert@gondor.apana.org.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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <limits.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#ifndef SSIZE_MAX
+#define SSIZE_MAX ((ssize_t)((size_t)-1 >> 1))
+#endif
+
+static inline void sigclearmask(void)
+{
+#ifdef HAVE_SIGSETMASK
+ sigsetmask(0);
+#else
+ sigset_t set;
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, 0);
+#endif
+}
+
+#ifndef HAVE_MEMPCPY
+void *mempcpy(void *, const void *, size_t);
+#endif
+
+#ifndef HAVE_STPCPY
+char *stpcpy(char *, const char *);
+#endif
+
+#ifndef HAVE_STRCHRNUL
+char *strchrnul(const char *, int);
+#endif
+
+#ifndef HAVE_STRSIGNAL
+char *strsignal(int);
+#endif
+
+#ifndef HAVE_STRTOIMAX
+#define strtoimax strtoll
+#endif
+
+#ifndef HAVE_STRTOUMAX
+#define strtoumax strtoull
+#endif
+
+#ifndef HAVE_BSEARCH
+void *bsearch(const void *, const void *, size_t, size_t,
+ int (*)(const void *, const void *));
+#endif
+
+#ifndef HAVE_KILLPG
+static inline int killpg(pid_t pid, int signal)
+{
+#ifdef DEBUG
+ if (pid < 0)
+ abort();
+#endif
+ return kill(-pid, signal);
+}
+#endif
+
+#ifndef HAVE_SYSCONF
+#define _SC_CLK_TCK 2
+long sysconf(int) __attribute__((__noreturn__));
+#endif
+
+#if !HAVE_DECL_ISBLANK
+int isblank(int c);
+#endif
+
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
diff --git a/usr/dash/trap.c b/usr/dash/trap.c
new file mode 100644
index 0000000..1e2a867
--- /dev/null
+++ b/usr/dash/trap.c
@@ -0,0 +1,467 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h" /* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+
+#ifdef HETIO
+#include "hetio.h"
+#endif
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes. A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1 /* default signal handling (SIG_DFL) */
+#define S_CATCH 2 /* signal is caught */
+#define S_IGN 3 /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4 /* signal is ignored permenantly */
+#define S_RESET 5 /* temporary - to reset a hard ignored sig */
+
+
+/* trap handler commands */
+static char *trap[NSIG];
+/* number of non-null traps */
+int trapcnt;
+/* current value of signal */
+char sigmode[NSIG - 1];
+/* indicates specified signal received */
+static char gotsig[NSIG - 1];
+/* last pending signal */
+volatile sig_atomic_t pendingsigs;
+/* received SIGCHLD */
+int gotsigchld;
+
+#ifdef mkinit
+INCLUDE "trap.h"
+INIT {
+ sigmode[SIGCHLD - 1] = S_DFL;
+ setsignal(SIGCHLD);
+}
+#endif
+
+/*
+ * The trap builtin.
+ */
+
+int
+trapcmd(int argc, char **argv)
+{
+ char *action;
+ char **ap;
+ int signo;
+
+ nextopt(nullstr);
+ ap = argptr;
+ if (!*ap) {
+ for (signo = 0 ; signo < NSIG ; signo++) {
+ if (trap[signo] != NULL) {
+ out1fmt(
+ "trap -- %s %s\n",
+ single_quote(trap[signo]),
+ signal_name(signo)
+ );
+ }
+ }
+ return 0;
+ }
+ if (!ap[1])
+ action = NULL;
+ else
+ action = *ap++;
+ while (*ap) {
+ if ((signo = decode_signal(*ap, 0)) < 0) {
+ outfmt(out2, "trap: %s: bad trap\n", *ap);
+ return 1;
+ }
+ INTOFF;
+ if (action) {
+ if (action[0] == '-' && action[1] == '\0')
+ action = NULL;
+ else {
+ if (*action)
+ trapcnt++;
+ action = savestr(action);
+ }
+ }
+ if (trap[signo]) {
+ if (*trap[signo])
+ trapcnt--;
+ ckfree(trap[signo]);
+ }
+ trap[signo] = action;
+ if (signo != 0)
+ setsignal(signo);
+ INTON;
+ ap++;
+ }
+ return 0;
+}
+
+
+
+/*
+ * Clear traps on a fork.
+ */
+
+void
+clear_traps(void)
+{
+ char **tp;
+
+ INTOFF;
+ for (tp = trap ; tp < &trap[NSIG] ; tp++) {
+ if (*tp && **tp) { /* trap not NULL or SIG_IGN */
+ ckfree(*tp);
+ *tp = NULL;
+ if (tp != &trap[0])
+ setsignal(tp - trap);
+ }
+ }
+ trapcnt = 0;
+ INTON;
+}
+
+
+
+/*
+ * Set the signal handler for the specified signal. The routine figures
+ * out what it should be set to.
+ */
+
+void
+setsignal(int signo)
+{
+ int action;
+ char *t, tsig;
+ struct sigaction act;
+
+ if ((t = trap[signo]) == NULL)
+ action = S_DFL;
+ else if (*t != '\0')
+ action = S_CATCH;
+ else
+ action = S_IGN;
+ if (rootshell && action == S_DFL) {
+ switch (signo) {
+ case SIGINT:
+ if (iflag || minusc || sflag == 0)
+ action = S_CATCH;
+ break;
+ case SIGQUIT:
+#ifdef DEBUG
+ if (debug)
+ break;
+#endif
+ /* FALLTHROUGH */
+ case SIGTERM:
+ if (iflag)
+ action = S_IGN;
+ break;
+#if JOBS
+ case SIGTSTP:
+ case SIGTTOU:
+ if (mflag)
+ action = S_IGN;
+ break;
+#endif
+ }
+ }
+
+ if (signo == SIGCHLD)
+ action = S_CATCH;
+
+ t = &sigmode[signo - 1];
+ tsig = *t;
+ if (tsig == 0) {
+ /*
+ * current setting unknown
+ */
+ if (sigaction(signo, 0, &act) == -1) {
+ /*
+ * Pretend it worked; maybe we should give a warning
+ * here, but other shells don't. We don't alter
+ * sigmode, so that we retry every time.
+ */
+ return;
+ }
+ if (act.sa_handler == SIG_IGN) {
+ if (mflag && (signo == SIGTSTP ||
+ signo == SIGTTIN || signo == SIGTTOU)) {
+ tsig = S_IGN; /* don't hard ignore these */
+ } else
+ tsig = S_HARD_IGN;
+ } else {
+ tsig = S_RESET; /* force to be set */
+ }
+ }
+ if (tsig == S_HARD_IGN || tsig == action)
+ return;
+ switch (action) {
+ case S_CATCH:
+ act.sa_handler = onsig;
+ break;
+ case S_IGN:
+ act.sa_handler = SIG_IGN;
+ break;
+ default:
+ act.sa_handler = SIG_DFL;
+ }
+ *t = action;
+ act.sa_flags = 0;
+ sigfillset(&act.sa_mask);
+ sigaction(signo, &act, 0);
+}
+
+/*
+ * Ignore a signal.
+ */
+
+void
+ignoresig(int signo)
+{
+ if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+ signal(signo, SIG_IGN);
+ }
+ sigmode[signo - 1] = S_HARD_IGN;
+}
+
+
+
+/*
+ * Signal handler.
+ */
+
+void
+onsig(int signo)
+{
+ if (signo == SIGCHLD) {
+ gotsigchld = 1;
+ if (!trap[SIGCHLD])
+ return;
+ }
+
+ gotsig[signo - 1] = 1;
+ pendingsigs = signo;
+
+ if (signo == SIGINT && !trap[SIGINT]) {
+ if (!suppressint)
+ onint();
+ intpending = 1;
+ }
+}
+
+
+
+/*
+ * Called to execute a trap. Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+
+void dotrap(void)
+{
+ char *p;
+ char *q;
+ int i;
+ int savestatus;
+
+ savestatus = exitstatus;
+ pendingsigs = 0;
+ barrier();
+
+ for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
+ if (!*q)
+ continue;
+ *q = 0;
+
+ p = trap[i + 1];
+ if (!p)
+ continue;
+ evalstring(p, 0);
+ exitstatus = savestatus;
+ if (evalskip)
+ break;
+ }
+}
+
+
+
+/*
+ * Controls whether the shell is interactive or not.
+ */
+
+
+void
+setinteractive(int on)
+{
+ static int is_interactive;
+
+ if (++on == is_interactive)
+ return;
+ is_interactive = on;
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+}
+
+
+
+/*
+ * Called to exit the shell.
+ */
+
+void
+exitshell(void)
+{
+ struct jmploc loc;
+ char *p;
+ volatile int status;
+
+#ifdef HETIO
+ hetio_reset_term();
+#endif
+ status = exitstatus;
+ TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+ if (setjmp(loc.loc)) {
+ if (exception == EXEXIT)
+ status = exitstatus;
+ goto out;
+ }
+ handler = &loc;
+ if ((p = trap[0])) {
+ trap[0] = NULL;
+ evalskip = 0;
+ evalstring(p, 0);
+ }
+out:
+ /*
+ * Disable job control so that whoever had the foreground before we
+ * started can get it back.
+ */
+ if (likely(!setjmp(loc.loc)))
+ setjobctl(0);
+ flushall();
+ _exit(status);
+ /* NOTREACHED */
+}
+
+/*
+ * Decode a signal name
+ */
+int decode_signal(const char *string, int minsig)
+{
+ int i;
+
+ if (is_number(string)) {
+ i = atoi(string);
+ if (i >= NSIG) {
+ return -1;
+ }
+ return i;
+ }
+
+ for ( i = minsig ; i < NSIG ; i++ ) {
+ if ( sys_sigabbrev[i] &&
+ !strcasecmp(string, sys_sigabbrev[i]) )
+ return i;
+ }
+
+#ifdef SIGRTMIN
+ if ( !strncasecmp(string, "RTMIN", 5) ) {
+ char *ep;
+
+ if ( string[5] && string[5] != '+' )
+ return -1;
+ i = SIGRTMIN + strtol(string+5, &ep, 10);
+ if ( *ep || i < SIGRTMIN || i > SIGRTMAX )
+ return -1;
+ return i;
+ }
+
+ if ( !strncasecmp(string, "RTMAX", 5) ) {
+ char *ep;
+
+ if ( string[5] && string[5] != '-' )
+ return -1;
+ i = SIGRTMAX + strtol(string+5, &ep, 10);
+ if ( *ep || i < SIGRTMIN || i > SIGRTMAX )
+ return -1;
+ return i;
+ }
+#endif
+
+ return -1;
+}
+
+/*
+ * Human-readable signal name
+ */
+const char *
+signal_name(int sig)
+{
+ static char buf[64];
+
+ if ( sig < 0 || sig >= NSIG ) {
+ return NULL;
+ } else if ( sys_sigabbrev[sig] ) {
+ return sys_sigabbrev[sig];
+#ifdef SIGRTMIN
+ } else if ( sig >= SIGRTMIN && sig <= SIGRTMAX ) {
+ snprintf(buf, sizeof buf, "RTMIN+%d", sig-SIGRTMIN);
+ return buf;
+#endif
+ } else {
+ snprintf(buf, sizeof buf, "%d", sig);
+ return buf;
+ }
+}
diff --git a/usr/dash/trap.h b/usr/dash/trap.h
new file mode 100644
index 0000000..6590be1
--- /dev/null
+++ b/usr/dash/trap.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.h 8.3 (Berkeley) 6/5/95
+ */
+
+#include <signal.h>
+
+extern int trapcnt;
+extern char sigmode[];
+extern volatile sig_atomic_t pendingsigs;
+extern int gotsigchld;
+
+int trapcmd(int, char **);
+void clear_traps(void);
+void setsignal(int);
+void ignoresig(int);
+void onsig(int);
+void dotrap(void);
+void setinteractive(int);
+void exitshell(void) __attribute__((__noreturn__));
+int decode_signal(const char *, int);
+const char *signal_name(int);
+
+static inline int have_traps(void)
+{
+ return trapcnt;
+}
diff --git a/usr/dash/var.c b/usr/dash/var.c
new file mode 100644
index 0000000..dc90249
--- /dev/null
+++ b/usr/dash/var.c
@@ -0,0 +1,710 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+/*
+ * Shell variables.
+ */
+
+#include "shell.h"
+#include "output.h"
+#include "expand.h"
+#include "nodes.h" /* for other headers */
+#include "exec.h"
+#include "syntax.h"
+#include "options.h"
+#include "mail.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "parser.h"
+#include "show.h"
+#ifndef SMALL
+#include "myhistedit.h"
+#endif
+#include "system.h"
+
+
+#define VTABSIZE 39
+
+
+struct localvar_list {
+ struct localvar_list *next;
+ struct localvar *lv;
+};
+
+MKINIT struct localvar_list *localvar_stack;
+
+const char defpathvar[] =
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+#ifdef IFS_BROKEN
+const char defifsvar[] = "IFS= \t\n";
+#else
+const char defifs[] = " \t\n";
+#endif
+
+int lineno;
+char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO=";
+
+/* Some macros in var.h depend on the order, add new variables to the end. */
+struct var varinit[] = {
+#if ATTY
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY\0", 0 },
+#endif
+#ifdef IFS_BROKEN
+ { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
+#else
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
+#endif
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
+ { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
+ { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
+ { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
+ { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
+ { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
+#ifdef WITH_LINENO
+ { 0, VSTRFIXED|VTEXTFIXED, linenovar, 0 },
+#endif
+#ifndef SMALL
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM\0", 0 },
+ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE\0", sethistsize },
+#endif
+};
+
+STATIC struct var *vartab[VTABSIZE];
+
+STATIC struct var **hashvar(const char *);
+STATIC int vpcmp(const void *, const void *);
+STATIC struct var **findvar(struct var **, const char *);
+
+/*
+ * Initialize the varable symbol tables and import the environment
+ */
+
+#ifdef mkinit
+INCLUDE <unistd.h>
+INCLUDE <sys/types.h>
+INCLUDE <sys/stat.h>
+INCLUDE "cd.h"
+INCLUDE "output.h"
+INCLUDE "var.h"
+MKINIT char **environ;
+INIT {
+ char **envp;
+ static char ppid[32] = "PPID=";
+ const char *p;
+ struct stat st1, st2;
+
+ initvar();
+ for (envp = environ ; *envp ; envp++) {
+ p = endofname(*envp);
+ if (p != *envp && *p == '=') {
+ setvareq(*envp, VEXPORT|VTEXTFIXED);
+ }
+ }
+
+ fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
+ setvareq(ppid, VTEXTFIXED);
+
+ p = lookupvar("PWD");
+ if (p)
+ if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
+ st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ p = 0;
+ setpwd(p, 0);
+}
+
+RESET {
+ unwindlocalvars(0);
+}
+#endif
+
+
+/*
+ * This routine initializes the builtin variables. It is called when the
+ * shell is initialized.
+ */
+
+void
+initvar(void)
+{
+ struct var *vp;
+ struct var *end;
+ struct var **vpp;
+
+ vp = varinit;
+ end = vp + sizeof(varinit) / sizeof(varinit[0]);
+ do {
+ vpp = hashvar(vp->text);
+ vp->next = *vpp;
+ *vpp = vp;
+ } while (++vp < end);
+ /*
+ * PS1 depends on uid
+ */
+ if (!geteuid())
+ vps1.text = "PS1=# ";
+}
+
+/*
+ * Set the value of a variable. The flags argument is ored with the
+ * flags of the variable. If val is NULL, the variable is unset.
+ */
+
+struct var *setvar(const char *name, const char *val, int flags)
+{
+ char *p, *q;
+ size_t namelen;
+ char *nameeq;
+ size_t vallen;
+ struct var *vp;
+
+ q = endofname(name);
+ p = strchrnul(q, '=');
+ namelen = p - name;
+ if (!namelen || p != q)
+ sh_error("%.*s: bad variable name", namelen, name);
+ vallen = 0;
+ if (val == NULL) {
+ flags |= VUNSET;
+ } else {
+ vallen = strlen(val);
+ }
+ INTOFF;
+ p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
+ if (val) {
+ *p++ = '=';
+ p = mempcpy(p, val, vallen);
+ }
+ *p = '\0';
+ vp = setvareq(nameeq, flags | VNOSAVE);
+ INTON;
+
+ return vp;
+}
+
+/*
+ * Set the given integer as the value of a variable. The flags argument is
+ * ored with the flags of the variable.
+ */
+
+intmax_t setvarint(const char *name, intmax_t val, int flags)
+{
+ int len = max_int_length(sizeof(val));
+ char buf[len];
+
+ fmtstr(buf, len, "%" PRIdMAX, val);
+ setvar(name, buf, flags);
+ return val;
+}
+
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value. Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ * Called with interrupts off.
+ */
+
+struct var *setvareq(char *s, int flags)
+{
+ struct var *vp, **vpp;
+
+ vpp = hashvar(s);
+ flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
+ vpp = findvar(vpp, s);
+ vp = *vpp;
+ if (vp) {
+ if (vp->flags & VREADONLY) {
+ const char *n;
+
+ if (flags & VNOSAVE)
+ free(s);
+ n = vp->text;
+ sh_error("%.*s: is read only", strchrnul(n, '=') - n,
+ n);
+ }
+
+ if (flags & VNOSET)
+ goto out;
+
+ if (vp->func && (flags & VNOFUNC) == 0)
+ (*vp->func)(strchrnul(s, '=') + 1);
+
+ if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(vp->text);
+
+ if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) |
+ (vp->flags & VSTRFIXED)) == VUNSET) {
+ *vpp = vp->next;
+ ckfree(vp);
+out_free:
+ if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
+ ckfree(s);
+ goto out;
+ }
+
+ flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
+ } else {
+ if (flags & VNOSET)
+ goto out;
+ if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
+ goto out_free;
+ /* not found */
+ vp = ckmalloc(sizeof (*vp));
+ vp->next = *vpp;
+ vp->func = NULL;
+ *vpp = vp;
+ }
+ if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
+ s = savestr(s);
+ vp->text = s;
+ vp->flags = flags;
+
+out:
+ return vp;
+}
+
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+void
+listsetvar(struct strlist *list, int flags)
+{
+ struct strlist *lp;
+
+ lp = list;
+ if (!lp)
+ return;
+ INTOFF;
+ do {
+ setvareq(lp->text, flags);
+ } while ((lp = lp->next));
+ INTON;
+}
+
+
+/*
+ * Find the value of a variable. Returns NULL if not set.
+ */
+
+char *
+lookupvar(const char *name)
+{
+ struct var *v;
+
+ if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
+#ifdef WITH_LINENO
+ if (v == &vlineno && v->text == linenovar) {
+ fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
+ }
+#endif
+ return strchrnul(v->text, '=') + 1;
+ }
+ return NULL;
+}
+
+intmax_t lookupvarint(const char *name)
+{
+ return atomax(lookupvar(name) ?: nullstr, 0);
+}
+
+
+
+/*
+ * Generate a list of variables satisfying the given conditions.
+ */
+
+char **
+listvars(int on, int off, char ***end)
+{
+ struct var **vpp;
+ struct var *vp;
+ char **ep;
+ int mask;
+
+ STARTSTACKSTR(ep);
+ vpp = vartab;
+ mask = on | off;
+ do {
+ for (vp = *vpp ; vp ; vp = vp->next)
+ if ((vp->flags & mask) == on) {
+ if (ep == stackstrend())
+ ep = growstackstr();
+ *ep++ = (char *) vp->text;
+ }
+ } while (++vpp < vartab + VTABSIZE);
+ if (ep == stackstrend())
+ ep = growstackstr();
+ if (end)
+ *end = ep;
+ *ep++ = NULL;
+ return grabstackstr(ep);
+}
+
+
+
+/*
+ * POSIX requires that 'set' (but not export or readonly) output the
+ * variables in lexicographic order - by the locale's collating order (sigh).
+ * Maybe we could keep them in an ordered balanced binary tree
+ * instead of hashed lists.
+ * For now just roll 'em through qsort for printing...
+ */
+
+int
+showvars(const char *prefix, int on, int off)
+{
+ const char *sep;
+ char **ep, **epend;
+
+ ep = listvars(on, off, &epend);
+ qsort(ep, epend - ep, sizeof(char *), vpcmp);
+
+ sep = *prefix ? spcstr : prefix;
+
+ for (; ep < epend; ep++) {
+ const char *p;
+ const char *q;
+
+ p = strchrnul(*ep, '=');
+ q = nullstr;
+ if (*p)
+ q = single_quote(++p);
+
+ out1fmt("%s%s%.*s%s\n", prefix, sep, (int)(p - *ep), *ep, q);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+int
+exportcmd(int argc, char **argv)
+{
+ struct var *vp;
+ char *name;
+ const char *p;
+ char **aptr;
+ int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+ int notp;
+
+ notp = nextopt("p") - 'p';
+ if (notp && ((name = *(aptr = argptr)))) {
+ do {
+ if ((p = strchr(name, '=')) != NULL) {
+ p++;
+ } else {
+ if ((vp = *findvar(hashvar(name), name))) {
+ vp->flags |= flag;
+ continue;
+ }
+ }
+ setvar(name, p, flag);
+ } while ((name = *++aptr) != NULL);
+ } else {
+ showvars(argv[0], flag, 0);
+ }
+ return 0;
+}
+
+
+/*
+ * The "local" command.
+ */
+
+int
+localcmd(int argc, char **argv)
+{
+ char *name;
+
+ if (!localvar_stack)
+ sh_error("not in a function");
+
+ argv = argptr;
+ while ((name = *argv++) != NULL) {
+ mklocal(name);
+ }
+ return 0;
+}
+
+
+/*
+ * Make a variable a local variable. When a variable is made local, it's
+ * value and flags are saved in a localvar structure. The saved values
+ * will be restored when the shell function returns. We handle the name
+ * "-" as a special case.
+ */
+
+void mklocal(char *name)
+{
+ struct localvar *lvp;
+ struct var **vpp;
+ struct var *vp;
+
+ INTOFF;
+ lvp = ckmalloc(sizeof (struct localvar));
+ if (name[0] == '-' && name[1] == '\0') {
+ char *p;
+ p = ckmalloc(sizeof(optlist));
+ lvp->text = memcpy(p, optlist, sizeof(optlist));
+ vp = NULL;
+ } else {
+ char *eq;
+
+ vpp = hashvar(name);
+ vp = *findvar(vpp, name);
+ eq = strchr(name, '=');
+ if (vp == NULL) {
+ if (eq)
+ vp = setvareq(name, VSTRFIXED);
+ else
+ vp = setvar(name, NULL, VSTRFIXED);
+ lvp->flags = VUNSET;
+ } else {
+ lvp->text = vp->text;
+ lvp->flags = vp->flags;
+ vp->flags |= VSTRFIXED|VTEXTFIXED;
+ if (eq)
+ setvareq(name, 0);
+ }
+ }
+ lvp->vp = vp;
+ lvp->next = localvar_stack->lv;
+ localvar_stack->lv = lvp;
+ INTON;
+}
+
+
+/*
+ * Called after a function returns.
+ * Interrupts must be off.
+ */
+
+void
+poplocalvars(int keep)
+{
+ struct localvar_list *ll;
+ struct localvar *lvp, *next;
+ struct var *vp;
+
+ INTOFF;
+ ll = localvar_stack;
+ localvar_stack = ll->next;
+
+ next = ll->lv;
+ ckfree(ll);
+
+ while ((lvp = next) != NULL) {
+ next = lvp->next;
+ vp = lvp->vp;
+ TRACE(("poplocalvar %s", vp ? vp->text : "-"));
+ if (keep) {
+ int bits = VSTRFIXED;
+
+ if (lvp->flags != VUNSET) {
+ if (vp->text == lvp->text)
+ bits |= VTEXTFIXED;
+ else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
+ ckfree(lvp->text);
+ }
+
+ vp->flags &= ~bits;
+ vp->flags |= (lvp->flags & bits);
+
+ if ((vp->flags &
+ (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
+ unsetvar(vp->text);
+ } else if (vp == NULL) { /* $- saved */
+ memcpy(optlist, lvp->text, sizeof(optlist));
+ ckfree(lvp->text);
+ optschanged();
+ } else if (lvp->flags == VUNSET) {
+ vp->flags &= ~(VSTRFIXED|VREADONLY);
+ unsetvar(vp->text);
+ } else {
+ if (vp->func)
+ (*vp->func)(strchrnul(lvp->text, '=') + 1);
+ if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(vp->text);
+ vp->flags = lvp->flags;
+ vp->text = lvp->text;
+ }
+ ckfree(lvp);
+ }
+ INTON;
+}
+
+
+/*
+ * Create a new localvar environment.
+ */
+struct localvar_list *pushlocalvars(void)
+{
+ struct localvar_list *ll;
+
+ INTOFF;
+ ll = ckmalloc(sizeof(*ll));
+ ll->lv = NULL;
+ ll->next = localvar_stack;
+ localvar_stack = ll;
+ INTON;
+
+ return ll->next;
+}
+
+
+void unwindlocalvars(struct localvar_list *stop)
+{
+ while (localvar_stack != stop)
+ poplocalvars(0);
+}
+
+
+/*
+ * The unset builtin command. We unset the function before we unset the
+ * variable to allow a function to be unset when there is a readonly variable
+ * with the same name.
+ */
+
+int
+unsetcmd(int argc, char **argv)
+{
+ char **ap;
+ int i;
+ int flag = 0;
+
+ while ((i = nextopt("vf")) != '\0') {
+ flag = i;
+ }
+
+ for (ap = argptr; *ap ; ap++) {
+ if (flag != 'f') {
+ unsetvar(*ap);
+ continue;
+ }
+ if (flag != 'v')
+ unsetfunc(*ap);
+ }
+ return 0;
+}
+
+
+/*
+ * Unset the specified variable.
+ */
+
+void unsetvar(const char *s)
+{
+ setvar(s, 0, 0);
+}
+
+
+
+/*
+ * Find the appropriate entry in the hash table from the name.
+ */
+
+STATIC struct var **
+hashvar(const char *p)
+{
+ unsigned int hashval;
+
+ hashval = ((unsigned char) *p) << 4;
+ while (*p && *p != '=')
+ hashval += (unsigned char) *p++;
+ return &vartab[hashval % VTABSIZE];
+}
+
+
+
+/*
+ * Compares two strings up to the first = or '\0'. The first
+ * string must be terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+int
+varcmp(const char *p, const char *q)
+{
+ int c, d;
+
+ while ((c = *p) == (d = *q)) {
+ if (!c || c == '=')
+ goto out;
+ p++;
+ q++;
+ }
+ if (c == '=')
+ c = 0;
+ if (d == '=')
+ d = 0;
+out:
+ return c - d;
+}
+
+STATIC int
+vpcmp(const void *a, const void *b)
+{
+ return varcmp(*(const char **)a, *(const char **)b);
+}
+
+STATIC struct var **
+findvar(struct var **vpp, const char *name)
+{
+ for (; *vpp; vpp = &(*vpp)->next) {
+ if (varequal((*vpp)->text, name)) {
+ break;
+ }
+ }
+ return vpp;
+}
diff --git a/usr/dash/var.h b/usr/dash/var.h
new file mode 100644
index 0000000..1a06a3c
--- /dev/null
+++ b/usr/dash/var.h
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)var.h 8.2 (Berkeley) 5/4/95
+ */
+
+#include <inttypes.h>
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT 0x01 /* variable is exported */
+#define VREADONLY 0x02 /* variable cannot be modified */
+#define VSTRFIXED 0x04 /* variable struct is statically allocated */
+#define VTEXTFIXED 0x08 /* text is statically allocated */
+#define VSTACK 0x10 /* text is allocated on the stack */
+#define VUNSET 0x20 /* the variable is not set */
+#define VNOFUNC 0x40 /* don't call the callback function */
+#define VNOSET 0x80 /* do not set variable - just readonly test */
+#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
+
+
+struct var {
+ struct var *next; /* next entry in hash list */
+ int flags; /* flags are defined above */
+ const char *text; /* name=value */
+ void (*func)(const char *);
+ /* function to be called when */
+ /* the variable gets set/unset */
+};
+
+
+struct localvar {
+ struct localvar *next; /* next local variable in list */
+ struct var *vp; /* the variable that was made local */
+ int flags; /* saved flags */
+ const char *text; /* saved text */
+};
+
+struct localvar_list;
+
+
+extern struct localvar *localvars;
+extern struct var varinit[];
+
+#if ATTY
+#define vatty varinit[0]
+#define vifs varinit[1]
+#else
+#define vifs varinit[0]
+#endif
+#define vmail (&vifs)[1]
+#define vmpath (&vmail)[1]
+#define vpath (&vmpath)[1]
+#define vps1 (&vpath)[1]
+#define vps2 (&vps1)[1]
+#define vps4 (&vps2)[1]
+#define voptind (&vps4)[1]
+#ifdef WITH_LINENO
+#define vlineno (&voptind)[1]
+#endif
+#ifndef SMALL
+#ifdef WITH_LINENO
+#define vterm (&vlineno)[1]
+#else
+#define vterm (&voptind)[1]
+#endif
+#define vhistsize (&vterm)[1]
+#endif
+
+#ifdef IFS_BROKEN
+extern const char defifsvar[];
+#define defifs (defifsvar + 4)
+#else
+extern const char defifs[];
+#endif
+extern const char defpathvar[];
+#define defpath (defpathvar + 5)
+
+extern int lineno;
+extern char linenovar[];
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name. They return the null string
+ * for unset variables.
+ */
+
+#define ifsval() (vifs.text + 4)
+#define ifsset() ((vifs.flags & VUNSET) == 0)
+#define mailval() (vmail.text + 5)
+#define mpathval() (vmpath.text + 9)
+#define pathval() (vpath.text + 5)
+#define ps1val() (vps1.text + 4)
+#define ps2val() (vps2.text + 4)
+#define ps4val() (vps4.text + 4)
+#define optindval() (voptind.text + 7)
+#define linenoval() (vlineno.text + 7)
+#ifndef SMALL
+#define histsizeval() (vhistsize.text + 9)
+#define termval() (vterm.text + 5)
+#endif
+
+#if ATTY
+#define attyset() ((vatty.flags & VUNSET) == 0)
+#endif
+#define mpathset() ((vmpath.flags & VUNSET) == 0)
+
+void initvar(void);
+struct var *setvar(const char *name, const char *val, int flags);
+intmax_t setvarint(const char *, intmax_t, int);
+struct var *setvareq(char *s, int flags);
+struct strlist;
+void listsetvar(struct strlist *, int);
+char *lookupvar(const char *);
+intmax_t lookupvarint(const char *);
+char **listvars(int, int, char ***);
+#define environment() listvars(VEXPORT, VUNSET, 0)
+int showvars(const char *, int, int);
+int exportcmd(int, char **);
+int localcmd(int, char **);
+void mklocal(char *);
+struct localvar_list *pushlocalvars(void);
+void poplocalvars(int);
+void unwindlocalvars(struct localvar_list *stop);
+int unsetcmd(int, char **);
+void unsetvar(const char *);
+int varcmp(const char *, const char *);
+
+static inline int varequal(const char *a, const char *b) {
+ return !varcmp(a, b);
+}
+
+/*
+ * Search the environment of a builtin command.
+ */
+
+static inline char *bltinlookup(const char *name)
+{
+ return lookupvar(name);
+}
diff --git a/usr/gzip/.gitignore b/usr/gzip/.gitignore
new file mode 100644
index 0000000..b665e3f
--- /dev/null
+++ b/usr/gzip/.gitignore
@@ -0,0 +1,3 @@
+gunzip
+gzip
+zcat
diff --git a/usr/gzip/COPYING b/usr/gzip/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/usr/gzip/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/usr/gzip/Kbuild b/usr/gzip/Kbuild
new file mode 100644
index 0000000..52c57d0
--- /dev/null
+++ b/usr/gzip/Kbuild
@@ -0,0 +1,26 @@
+#
+# Kbuild file for gzip
+#
+
+# The gzip executable
+static-y := gzip
+gzip-y := gzip.o util.o unzip.o inflate.o
+
+# Additional targets
+always := gunzip zcat
+
+# Optional ZIP support
+gzip-$(CONFIG_KLIBC_ZIP) += zip.o deflate.o trees.o bits.o
+cflags-$(CONFIG_KLIBC_ZIP) += -DSUPPORT_ZIP
+EXTRA_KLIBCCFLAGS := $(cflags-y)
+
+# Additionally linked targets
+$(obj)/gunzip $(obj)/zcat: $(obj)/gzip
+ $(call cmd,ln)
+
+# Cleaning
+targets := gzip gzip.g gunzip zcat
+
+# Targets to install
+install-y := gzip
+install-link-y := gunzip=gzip zcat=gzip
diff --git a/usr/gzip/README b/usr/gzip/README
new file mode 100644
index 0000000..fdd7311
--- /dev/null
+++ b/usr/gzip/README
@@ -0,0 +1,144 @@
+This is the file README for the gzip distribution, version 1.2.4.
+
+gzip (GNU zip) is a compression utility designed to be a replacement
+for 'compress'. Its main advantages over compress are much better
+compression and freedom from patented algorithms. The GNU Project
+uses it as the standard compression program for its system.
+
+gzip currently uses by default the LZ77 algorithm used in zip 1.9 (the
+portable pkzip compatible archiver). The gzip format was however
+designed to accommodate several compression algorithms. See below
+for a comparison of zip and gzip.
+
+gunzip can currently decompress files created by gzip, compress or
+pack. The detection of the input format is automatic. For the
+gzip format, gunzip checks a 32 bit CRC. For pack, gunzip checks the
+uncompressed length. The 'compress' format was not designed to allow
+consistency checks. However gunzip is sometimes able to detect a bad
+.Z file because there is some redundancy in the .Z compression format.
+If you get an error when uncompressing a .Z file, do not assume that
+the .Z file is correct simply because the standard uncompress does not
+complain. This generally means that the standard uncompress does not
+check its input, and happily generates garbage output.
+
+gzip produces files with a .gz extension. Previous versions of gzip
+used the .z extension, which was already used by the 'pack'
+Huffman encoder. gunzip is able to decompress .z files (packed
+or gzip'ed).
+
+Several planned features are not yet supported (see the file TODO).
+See the file NEWS for a summary of changes since 0.5. See the file
+INSTALL for installation instructions. Some answers to frequently
+asked questions are given in the file INSTALL, please read it. (In
+particular, please don't ask me once more for an /etc/magic entry.)
+
+WARNING: on several systems, compiler bugs cause gzip to fail, in
+particular when optimization options are on. See the section "Special
+targets" at the end of the INSTALL file for a list of known problems.
+For all machines, use "make check" to check that gzip was compiled
+correctly. Try compiling gzip without any optimization if you have a
+problem.
+
+Please send all comments and bug reports by electronic mail to:
+ Jean-loup Gailly <jloup@chorus.fr>
+
+or, if this fails, to bug-gnu-utils@prep.ai.mit.edu.
+Bug reports should ideally include:
+
+ * The complete output of "gzip -V" (or the contents of revision.h
+ if you can't get gzip to compile)
+ * The hardware and operating system (try "uname -a")
+ * The compiler used to compile (if it is gcc, use "gcc -v")
+ * A description of the bug behavior
+ * The input to gzip, that triggered the bug
+
+If you send me patches for machines I don't have access to, please test them
+very carefully. gzip is used for backups, it must be extremely reliable.
+
+The package crypt++.el is highly recommended to manipulate gzip'ed
+file from emacs. It recognizes automatically encrypted and compressed
+files when they are first visited or written. It is available via
+anonymous ftp to roebling.poly.edu [128.238.5.31] in /pub/crypt++.el.
+The same directory contains also patches to dired, ange-ftp and info.
+GNU tar 1.11.2 has a -z option to invoke directly gzip, so you don't have to
+patch it. The package ftp.uu.net:/languages/emacs-lisp/misc/jka-compr19.el.Z
+also supports gzip'ed files.
+
+The znew and gzexe shell scripts provided with gzip benefit from
+(but do not require) the cpmod utility to transfer file attributes.
+It is available by anonymous ftp on gatekeeper.dec.com in
+/.0/usenet/comp.sources.unix/volume11/cpmod.Z.
+
+The sample programs zread.c, sub.c and add.c in subdirectory sample
+are provided as examples of useful complements to gzip. Read the
+comments inside each source file. The perl script ztouch is also
+provided as example (not installed by default since it relies on perl).
+
+
+gzip is free software, you can redistribute it and/or modify it under
+the terms of the GNU General Public License, a copy of which is
+provided under the name COPYING. The latest version of gzip are always
+available by ftp in prep.ai.mit.edu:/pub/gnu, or in any of the prep
+mirror sites:
+
+- sources in gzip-*.tar (or .shar or .tar.gz).
+- Solaris 2 executables in sparc-sun-solaris2/gzip-binaries-*.tar
+- MSDOS lha self-extracting exe in gzip-msdos-*.exe. Once extracted,
+ copy gzip.exe to gunzip.exe and zcat.exe, or use "gzip -d" to decompress.
+ gzip386.exe runs much faster but only on 386 and above; it is compiled with
+ djgpp 1.10 available in directory omnigate.clarkson.edu:/pub/msdos/djgpp.
+
+A VMS executable is available in ftp.spc.edu:[.macro32.savesets]gzip-1-*.zip
+(use [.macro32]unzip.exe to extract). A PRIMOS executable is available
+in ftp.lysator.liu.se:/pub/primos/run/gzip.run.
+OS/2 executables (16 and 32 bits versions) are available in
+ftp.tu-muenchen.de:/pub/comp/os/os2/archiver/gz*-[16,32].zip
+
+Some ftp servers can automatically make a tar.Z from a tar file. If
+you are getting gzip for the first time, you can ask for a tar.Z file
+instead of the much larger tar file.
+
+Many thanks to those who provided me with bug reports and feedback.
+See the files THANKS and ChangeLog for more details.
+
+
+ Note about zip vs. gzip:
+
+The name 'gzip' was a very unfortunate choice, because zip and gzip
+are two really different programs, although the actual compression and
+decompression sources were written by the same persons. A different
+name should have been used for gzip, but it is too late to change now.
+
+zip is an archiver: it compresses several files into a single archive
+file. gzip is a simple compressor: each file is compressed separately.
+Both share the same compression and decompression code for the
+'deflate' method. unzip can also decompress old zip archives
+(implode, shrink and reduce methods). gunzip can also decompress files
+created by compress and pack. zip 1.9 and gzip do not support
+compression methods other than deflation. (zip 1.0 supports shrink and
+implode). Better compression methods may be added in future versions
+of gzip. zip will always stick to absolute compatibility with pkzip,
+it is thus constrained by PKWare, which is a commercial company. The
+gzip header format is deliberately different from that of pkzip to
+avoid such a constraint.
+
+On Unix, gzip is mostly useful in combination with tar. GNU tar
+1.11.2 has a -z option to invoke gzip automatically. "tar -z"
+compresses better than zip, since gzip can then take advantage of
+redundancy between distinct files. The drawback is that you must
+scan the whole tar.gz file in order to extract a single file near
+the end; unzip can directly seek to the end of the zip file. There
+is no overhead when you extract the whole archive anyway.
+If a member of a .zip archive is damaged, other files can still
+be recovered. If a .tar.gz file is damaged, files beyond the failure
+point cannot be recovered. (Future versions of gzip will have
+error recovery features.)
+
+gzip and gunzip are distributed as a single program. zip and unzip
+are, for historical reasons, two separate programs, although the
+authors of these two programs work closely together in the info-zip
+team. zip and unzip are not associated with the GNU project.
+The sources are available by ftp in
+
+ oak.oakland.edu:/pub/misc/unix/zip19p1.zip
+ oak.oakland.edu:/pub/misc/unix/unz50p1.tar-z
diff --git a/usr/gzip/bits.c b/usr/gzip/bits.c
new file mode 100644
index 0000000..4707a08
--- /dev/null
+++ b/usr/gzip/bits.c
@@ -0,0 +1,200 @@
+/* bits.c -- output variable-length bit strings
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+
+/*
+ * PURPOSE
+ *
+ * Output variable-length bit strings. Compression can be done
+ * to a file or to memory. (The latter is not supported in this version.)
+ *
+ * DISCUSSION
+ *
+ * The PKZIP "deflate" file format interprets compressed file data
+ * as a sequence of bits. Multi-bit strings in the file may cross
+ * byte boundaries without restriction.
+ *
+ * The first bit of each byte is the low-order bit.
+ *
+ * The routines in this file allow a variable-length bit value to
+ * be output right-to-left (useful for literal values). For
+ * left-to-right output (useful for code strings from the tree routines),
+ * the bits must have been reversed first with bi_reverse().
+ *
+ * For in-memory compression, the compressed bit stream goes directly
+ * into the requested output buffer. The input data is read in blocks
+ * by the mem_read() function. The buffer is limited to 64K on 16 bit
+ * machines.
+ *
+ * INTERFACE
+ *
+ * void bi_init (FILE *zipfile)
+ * Initialize the bit string routines.
+ *
+ * void send_bits (int value, int length)
+ * Write out a bit string, taking the source bits right to
+ * left.
+ *
+ * int bi_reverse (int value, int length)
+ * Reverse the bits of a bit string, taking the source bits left to
+ * right and emitting them right to left.
+ *
+ * void bi_windup (void)
+ * Write out any remaining bits in an incomplete byte.
+ *
+ * void copy_block(char *buf, unsigned len, int header)
+ * Copy a stored block to the zip file, storing first the length and
+ * its one's complement if requested.
+ *
+ */
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef DEBUG
+# include <stdio.h>
+#endif
+
+#ifdef RCSID
+static char rcsid[] = "$Id: bits.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Local data used by the "bit string" routines.
+ */
+
+local file_t zfile; /* output gzip file */
+
+local unsigned short bi_buf;
+/* Output buffer. bits are inserted starting at the bottom (least significant
+ * bits).
+ */
+
+#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 int bi_valid;
+/* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+int (*read_buf) OF((char *buf, unsigned size));
+/* Current input function. Set to mem_read for in-memory compression */
+
+#ifdef DEBUG
+ ulg bits_sent; /* bit length of the compressed data */
+#endif
+
+/* ===========================================================================
+ * Initialize the bit string routines.
+ */
+void bi_init (zipfile)
+ file_t zipfile; /* output zip file, NO_FILE for in-memory compression */
+{
+ zfile = zipfile;
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = 0L;
+#endif
+
+ /* Set the defaults for file compression. They are set by memcompress
+ * for in-memory compression.
+ */
+ if (zfile != NO_FILE) {
+ read_buf = file_read;
+ }
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+void send_bits(value, length)
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+#ifdef DEBUG
+ Tracev((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ bits_sent += (ulg)length;
+#endif
+ /* 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 (bi_valid > (int)Buf_size - length) {
+ bi_buf |= (value << bi_valid);
+ put_short(bi_buf);
+ bi_buf = (ush)value >> (Buf_size - bi_valid);
+ bi_valid += length - Buf_size;
+ } else {
+ bi_buf |= value << bi_valid;
+ bi_valid += length;
+ }
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+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;
+}
+
+/* ===========================================================================
+ * Write out any remaining bits in an incomplete byte.
+ */
+void bi_windup()
+{
+ if (bi_valid > 8) {
+ put_short(bi_buf);
+ } else if (bi_valid > 0) {
+ put_byte(bi_buf);
+ }
+ bi_buf = 0;
+ bi_valid = 0;
+#ifdef DEBUG
+ bits_sent = (bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block to the zip file, storing first the length and its
+ * one's complement if requested.
+ */
+void copy_block(buf, len, header)
+ char *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(); /* align on byte boundary */
+
+ if (header) {
+ put_short((ush)len);
+ put_short((ush)~len);
+#ifdef DEBUG
+ bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(*buf++);
+ }
+}
diff --git a/usr/gzip/deflate.c b/usr/gzip/deflate.c
new file mode 100644
index 0000000..1db44fd
--- /dev/null
+++ b/usr/gzip/deflate.c
@@ -0,0 +1,759 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ * PURPOSE
+ *
+ * Identify new text as repetitions of old text within a fixed-
+ * length sliding window trailing behind the new text.
+ *
+ * DISCUSSION
+ *
+ * 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 info-zippers for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * APPNOTE.TXT documentation file in PKZIP 1.93a distribution.
+ *
+ * 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
+ *
+ * INTERFACE
+ *
+ * void lm_init (int pack_level, ush *flags)
+ * Initialize the "longest match" routines for a new file
+ *
+ * ulg deflate (void)
+ * Processes a new input file and return its compressed length. Sets
+ * the compressed length, crc, deflate flags and internal file
+ * attributes.
+ */
+
+#include <stdio.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef RCSID
+static char rcsid[] = "$Id: deflate.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Configuration parameters
+ */
+
+/* Compile with MEDIUM_MEM to reduce the memory requirements or
+ * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the
+ * entire input file can be held in memory (not possible on 16 bit systems).
+ * Warning: defining these symbols affects HASH_BITS (see below) and thus
+ * affects the compression ratio. The compressed output
+ * is still correct, and might even be smaller in some cases.
+ */
+
+#ifdef SMALL_MEM
+# define HASH_BITS 13 /* Number of bits used to hash strings */
+#endif
+#ifdef MEDIUM_MEM
+# define HASH_BITS 14
+#endif
+#ifndef HASH_BITS
+# define HASH_BITS 15
+ /* For portability to 16 bit machines, do not use values above 15. */
+#endif
+
+/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and
+ * window with tab_suffix. Check that we can do this:
+ */
+#if (WSIZE<<1) > (1<<BITS)
+ error: cannot overlay window with tab_suffix and prev with tab_prefix0
+#endif
+#if HASH_BITS > BITS-1
+ error: cannot overlay head with tab_prefix1
+#endif
+
+#define HASH_SIZE (unsigned)(1<<HASH_BITS)
+#define HASH_MASK (HASH_SIZE-1)
+#define WMASK (WSIZE-1)
+/* HASH_SIZE and WSIZE must be powers of two */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#define FAST 4
+#define SLOW 2
+/* speed options for the general purpose bit flag */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* ===========================================================================
+ * Local data used by the "longest match" routines.
+ */
+
+typedef ush Pos;
+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.
+ */
+
+/* DECLARE(uch, window, 2L*WSIZE); */
+/* 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: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would
+ * be less efficient).
+ */
+
+/* DECLARE(Pos, prev, WSIZE); */
+/* 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.
+ */
+
+/* DECLARE(Pos, head, 1<<HASH_BITS); */
+/* Heads of the hash chains or NIL. */
+
+ulg window_size = (ulg)2*WSIZE;
+/* window size, 2*WSIZE except for MMAP or BIG_MEM, where it is the
+ * input file length plus MIN_LOOKAHEAD.
+ */
+
+long block_start;
+/* window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+local unsigned ins_h; /* hash index of string to be inserted */
+
+#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
+/* Number of bits by which ins_h and del_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:
+ * H_SHIFT * MIN_MATCH >= HASH_BITS
+ */
+
+unsigned int 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.
+ */
+
+ unsigned strstart; /* start of string to insert */
+ unsigned match_start; /* start of matching string */
+local int eofile; /* flag set at end of input file */
+local unsigned lookahead; /* number of valid bytes ahead in window */
+
+unsigned 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.
+ */
+
+local unsigned int 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.
+ */
+
+local int compr_level;
+/* compression level (1..9) */
+
+unsigned good_match;
+/* Use a faster search when the previous match is longer than this */
+
+
+/* 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 {
+ 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;
+} config;
+
+#ifdef FULL_SEARCH
+# define nice_match MAX_MATCH
+#else
+ int nice_match; /* Stop searching when current match exceeds this */
+#endif
+
+local config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0}, /* store only */
+/* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8},
+/* 3 */ {4, 6, 32, 32},
+
+/* 4 */ {4, 4, 16, 16}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32},
+/* 6 */ {8, 16, 128, 128},
+/* 7 */ {8, 32, 128, 256},
+/* 8 */ {32, 128, 258, 1024},
+/* 9 */ {32, 258, 258, 4096}}; /* maximum compression */
+
+/* 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 */
+
+/* ===========================================================================
+ * Prototypes for local functions.
+ */
+local void fill_window OF((void));
+local ulg deflate_fast OF((void));
+
+ int longest_match OF((IPos cur_match));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+#endif
+
+#ifdef DEBUG
+local void check_match OF((IPos start, IPos match, int length));
+#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(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
+
+/* ===========================================================================
+ * Insert string s 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.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of s are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, match_head) \
+ (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
+ prev[(s) & WMASK] = match_head = head[ins_h], \
+ head[ins_h] = (s))
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new file
+ */
+void lm_init (pack_level, flags)
+ int pack_level; /* 0: store, 1: best speed, 9: best compression */
+ ush *flags; /* general purpose bit flag */
+{
+ register unsigned j;
+
+ if (pack_level < 1 || pack_level > 9) error("bad pack level");
+ compr_level = pack_level;
+
+ /* Initialize the hash table. */
+ memzero((char*)head, HASH_SIZE*sizeof(*head));
+
+ /* prev will be initialized on the fly */
+
+ /* Set the default configuration parameters:
+ */
+ max_lazy_match = configuration_table[pack_level].max_lazy;
+ good_match = configuration_table[pack_level].good_length;
+#ifndef FULL_SEARCH
+ nice_match = configuration_table[pack_level].nice_length;
+#endif
+ max_chain_length = configuration_table[pack_level].max_chain;
+ if (pack_level == 1) {
+ *flags |= FAST;
+ } else if (pack_level == 9) {
+ *flags |= SLOW;
+ }
+ /* ??? reduce max_chain_length for binary files */
+
+ strstart = 0;
+ block_start = 0L;
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+
+ lookahead = read_buf((char*)window,
+ sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE);
+
+ if (lookahead == 0 || lookahead == (unsigned)EOF) {
+ eofile = 1, lookahead = 0;
+ return;
+ }
+ eofile = 0;
+ /* Make sure that we always have enough lookahead. This is important
+ * if input comes from a device such as a tty.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+ ins_h = 0;
+ for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
+ * not important since only literal bytes will be emitted.
+ */
+}
+
+/* ===========================================================================
+ * 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
+ */
+#ifndef ASMV
+/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or
+ * match.s. The code is functionally equivalent, so you can use the C version
+ * if desired.
+ */
+int longest_match(cur_match)
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = max_chain_length; /* max hash chain length */
+ register uch *scan = window + strstart; /* current string */
+ register uch *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = prev_length; /* best match length so far */
+ IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+
+/* 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.
+ */
+#if HASH_BITS < 8 || MAX_MATCH != 258
+ error: Code too clever
+#endif
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register uch *strend = window + strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ush*)scan;
+ register ush scan_end = *(ush*)(scan+best_len-1);
+#else
+ register uch *strend = window + strstart + MAX_MATCH;
+ register uch scan_end1 = scan[best_len-1];
+ register uch scan_end = scan[best_len];
+#endif
+
+ /* Do not waste too much time if we already have a good match: */
+ if (prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+ Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
+
+ do {
+ Assert(cur_match < strstart, "no future");
+ match = window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2:
+ */
+#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 (*(ush*)(match+best_len-1) != scan_end ||
+ *(ush*)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.
+ */
+ scan++, match++;
+ do {
+ } while (*(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ *(ush*)(scan+=2) == *(ush*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= window+(unsigned)(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++;
+
+ /* 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);
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ush*)(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);
+
+ return best_len;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(start, match, length)
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (memcmp((char*)window + match,
+ (char*)window + start, length) != EQUAL) {
+ fprintf(stderr,
+ " start %d, match %d, length %d\n",
+ start, match, length);
+ error("invalid match");
+ }
+ if (verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead, and sets eofile if end of input file.
+ * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
+ * OUT assertions: at least one byte has been read, or eofile is set;
+ * file reads are performed for at least two bytes (required for the
+ * translate_eol option).
+ */
+local void fill_window()
+{
+ register unsigned n, m;
+ unsigned more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart);
+ /* Amount of free space at the end of the window. */
+
+ /* 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 (more == (unsigned)EOF) {
+ /* Very unlikely, but possible on 16 bit machine if strstart == 0
+ * and lookahead == 1 (input done one byte at time)
+ */
+ more--;
+ } else if (strstart >= WSIZE+MAX_DIST) {
+ /* By the IN assertion, the window is not empty so we can't confuse
+ * more == 0 with more == 64K on a 16 bit machine.
+ */
+ Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
+
+ memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
+ match_start -= WSIZE;
+ strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
+
+ block_start -= (long) WSIZE;
+
+ for (n = 0; n < HASH_SIZE; n++) {
+ m = head[n];
+ head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
+ }
+ for (n = 0; n < WSIZE; n++) {
+ m = prev[n];
+ prev[n] = (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.
+ */
+ }
+ more += WSIZE;
+ }
+ /* At this point, more >= 2 */
+ if (!eofile) {
+ n = read_buf((char*)window+strstart+lookahead, more);
+ if (n == 0 || n == (unsigned)EOF) {
+ eofile = 1;
+ } else {
+ lookahead += n;
+ }
+ }
+}
+
+/* ===========================================================================
+ * 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(eof) \
+ flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
+ (char*)NULL, (long)strstart - block_start, (eof))
+
+/* ===========================================================================
+ * Processes a new input file and return its compressed length. This
+ * function does not perform lazy evaluationof 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 ulg deflate_fast()
+{
+ IPos hash_head; /* head of the hash chain */
+ int flush; /* set if current block must be flushed */
+ unsigned match_length = 0; /* length of best match */
+
+ prev_length = MIN_MATCH-1;
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(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 && strstart - hash_head <= MAX_DIST) {
+ /* 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).
+ */
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+ }
+ if (match_length >= MIN_MATCH) {
+ check_match(strstart, match_start, match_length);
+
+ flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
+
+ lookahead -= match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+ if (match_length <= max_insert_length) {
+ match_length--; /* string at strstart already in hash table */
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since
+ * the next lookahead bytes will be emitted as literals.
+ */
+ } while (--match_length != 0);
+ strstart++;
+ } else {
+ strstart += match_length;
+ match_length = 0;
+ ins_h = window[strstart];
+ UPDATE_HASH(ins_h, window[strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c",window[strstart]));
+ flush = ct_tally (0, window[strstart]);
+ lookahead--;
+ strstart++;
+ }
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ /* 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.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+
+ }
+ return FLUSH_BLOCK(1); /* eof */
+}
+
+/* ===========================================================================
+ * 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.
+ */
+ulg deflate()
+{
+ IPos hash_head; /* head of hash chain */
+ IPos prev_match; /* previous match */
+ int flush; /* set if current block must be flushed */
+ int match_available = 0; /* set if previous match exists */
+ register unsigned match_length = MIN_MATCH-1; /* length of best match */
+#ifdef DEBUG
+ extern long isize; /* byte length of input file, for debug only */
+#endif
+
+ if (compr_level <= 3) return deflate_fast(); /* optimized for speed */
+
+ /* Process the input block. */
+ while (lookahead != 0) {
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ INSERT_STRING(strstart, hash_head);
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ prev_length = match_length, prev_match = match_start;
+ match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && prev_length < max_lazy_match &&
+ strstart - hash_head <= MAX_DIST) {
+ /* 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).
+ */
+ match_length = longest_match (hash_head);
+ /* longest_match() sets match_start */
+ if (match_length > lookahead) match_length = lookahead;
+
+ /* Ignore a length 3 match if it is too distant: */
+ if (match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ match_length--;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (prev_length >= MIN_MATCH && match_length <= prev_length) {
+
+ check_match(strstart-1, prev_match, prev_length);
+
+ flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted.
+ */
+ lookahead -= prev_length-1;
+ prev_length -= 2;
+ do {
+ strstart++;
+ INSERT_STRING(strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
+ * these bytes are garbage, but it does not matter since the
+ * next lookahead bytes will always be emitted as literals.
+ */
+ } while (--prev_length != 0);
+ match_available = 0;
+ match_length = MIN_MATCH-1;
+ strstart++;
+ if (flush) FLUSH_BLOCK(0), block_start = strstart;
+
+ } else if (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",window[strstart-1]));
+ if (ct_tally (0, window[strstart-1])) {
+ FLUSH_BLOCK(0), block_start = strstart;
+ }
+ strstart++;
+ lookahead--;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ match_available = 1;
+ strstart++;
+ lookahead--;
+ }
+ Assert (strstart <= isize && lookahead <= isize, "a bit too far");
+
+ /* 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.
+ */
+ while (lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
+ }
+ if (match_available) ct_tally (0, window[strstart-1]);
+
+ return FLUSH_BLOCK(1); /* eof */
+}
diff --git a/usr/gzip/gzip.c b/usr/gzip/gzip.c
new file mode 100644
index 0000000..d0c7e00
--- /dev/null
+++ b/usr/gzip/gzip.c
@@ -0,0 +1,1215 @@
+/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * The unzip code was written and put in the public domain by Mark Adler.
+ * Portions of the lzw code are derived from the public domain 'compress'
+ * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
+ * Ken Turkowski, Dave Mack and Peter Jannesen.
+ *
+ * See the license_msg below and the file COPYING for the software license.
+ * See the file algorithm.doc for the compression algorithms and file formats.
+ */
+
+static char *license_msg[] = {
+" Copyright (C) 1992-1993 Jean-loup Gailly",
+" This program is free software; you can redistribute it and/or modify",
+" it under the terms of the GNU General Public License as published by",
+" the Free Software Foundation; either version 2, or (at your option)",
+" any later version.",
+"",
+" This program is distributed in the hope that it will be useful,",
+" but WITHOUT ANY WARRANTY; without even the implied warranty of",
+" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
+" GNU General Public License for more details.",
+"",
+" You should have received a copy of the GNU General Public License",
+" along with this program; if not, write to the Free Software",
+" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.",
+0};
+
+/* Compress files with zip algorithm and 'compress' interface.
+ * See usage() and help() functions below for all options.
+ * Outputs:
+ * file.gz: compressed file with same mode, owner, and utimes
+ * or stdout with -c option or if stdin used as input.
+ * If the output file name had to be truncated, the original name is kept
+ * in the compressed file.
+ * On MSDOS, file.tmp -> file.tmz. On VMS, file.tmp -> file.tmp-gz.
+ *
+ * Using gz on MSDOS would create too many file name conflicts. For
+ * example, foo.txt -> foo.tgz (.tgz must be reserved as shorthand for
+ * tar.gz). Similarly, foo.dir and foo.doc would both be mapped to foo.dgz.
+ * I also considered 12345678.txt -> 12345txt.gz but this truncates the name
+ * too heavily. There is no ideal solution given the MSDOS 8+3 limitation.
+ *
+ * For the meaning of all compilation flags, see comments in Makefile.in.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: gzip.c,v 1.3 2005/02/12 21:03:28 olh Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#include "revision.h"
+
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <utime.h>
+
+typedef void (*sig_type) OF((int));
+
+#define RW_USER (S_IRUSR | S_IWUSR) /* creation mode for open() */
+
+#ifndef MAX_PATH_LEN
+# define MAX_PATH_LEN 1024 /* max pathname length */
+#endif
+
+ /* global buffers */
+
+DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(ush, d_buf, DIST_BUFSIZE);
+DECLARE(uch, window, 2L*WSIZE);
+DECLARE(ush, tab_prefix, 1L<<BITS);
+
+ /* local variables */
+
+#ifndef SUPPORT_ZIP
+#define decompress 1
+#else
+int level = 6; /* compression level */
+#endif
+
+int to_stdout; /* output to stdout (-c) */
+#ifdef decompress
+int decompress_wanted;
+#else
+int decompress; /* decompress (-d) */
+#define decompress_wanted decompress
+#endif
+int force; /* don't ask questions, compress links (-f) */
+int no_name = -1; /* don't save or restore the original file name */
+int no_time = -1; /* don't save or restore the original file time */
+int verbose; /* be verbose (-v) */
+int quiet; /* be very quiet (-q) */
+int test; /* test .gz file integrity */
+int foreground; /* set if program run in foreground */
+char *progname; /* program name */
+int method = DEFLATED;/* compression method */
+int exit_code = OK; /* program exit code */
+int save_orig_name; /* set if original name must be saved */
+int last_member; /* set for .zip and .Z files */
+int part_nb; /* number of parts in .gz file */
+time_t time_stamp; /* original time stamp (modification time) */
+long ifile_size; /* input file size, -1 for devices (debug only) */
+char *env; /* contents of GZIP env variable */
+char **args = NULL; /* argv pointer if GZIP env variable defined */
+char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
+int z_len; /* strlen(z_suffix) */
+
+long header_bytes; /* number of bytes in gzip header */
+long bytes_in; /* number of input bytes */
+long bytes_out; /* number of output bytes */
+long total_in; /* input bytes for all files */
+long total_out; /* output bytes for all files */
+char ifname[MAX_PATH_LEN]; /* input file name */
+char ofname[MAX_PATH_LEN]; /* output file name */
+int remove_ofname; /* remove output file on error */
+struct stat istat; /* status for input file */
+int ifd; /* input file descriptor */
+int ofd; /* output file descriptor */
+unsigned insize; /* valid bytes in inbuf */
+unsigned inptr; /* index of next byte to be processed in inbuf */
+unsigned outcnt; /* bytes in output buffer */
+
+/* local functions */
+
+local void usage OF((void));
+local void help OF((void));
+local void license OF((void));
+local void version OF((void));
+local void treat_stdin OF((void));
+local void treat_file OF((char *iname));
+local int create_outfile OF((void));
+local int do_stat OF((char *name, struct stat *sbuf));
+local char *get_suffix OF((char *name));
+local int get_istat OF((char *iname, struct stat *sbuf));
+local int make_ofname OF((void));
+local int same_file OF((struct stat *stat1, struct stat *stat2));
+local int name_too_long OF((char *name, struct stat *statb));
+local void shorten_name OF((char *name));
+local int get_method OF((void));
+local int check_ofname OF((void));
+local void copy_stat OF((struct stat *ifstat));
+local void do_exit OF((int exitcode));
+ int main OF((int argc, char **argv));
+int (*work) OF((int infile, int outfile))
+#ifdef SUPPORT_ZIP
+ = zip; /* function to call */
+#else
+ = unzip;
+#endif
+local void reset_times OF((char *name, struct stat *statb));
+
+#define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
+
+/* ======================================================================== */
+local void usage()
+{
+ fprintf(stderr, "usage: %s [-cdfhlLnNtvV19] [-S suffix] [file ...]\n",
+ progname);
+}
+
+/* ======================================================================== */
+local void help()
+{
+ static char *help_msg[] = {
+ " -c --stdout write on standard output, keep original files unchanged",
+ " -d --decompress decompress",
+ " -f --force force overwrite of output file and compress links",
+ " -h --help give this help",
+ " -L --license display software license",
+#ifdef UNDOCUMENTED
+ " -m --no-time do not save or restore the original modification time",
+ " -M --time save or restore the original modification time",
+#endif
+ " -n --no-name do not save or restore the original name and time stamp",
+ " -N --name save or restore the original name and time stamp",
+ " -q --quiet suppress all warnings",
+ " -S .suf --suffix .suf use suffix .suf on compressed files",
+ " -t --test test compressed file integrity",
+ " -v --verbose verbose mode",
+ " -V --version display version number",
+#ifdef SUPPORT_ZIP
+ " -1 --fast compress faster",
+ " -9 --best compress better",
+ " file... files to (de)compress. If none given, use standard input.",
+#else
+ " file... files to decompress. If none given, use standard input.",
+#endif
+ 0};
+ char **p = help_msg;
+
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+ usage();
+ while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void license()
+{
+ char **p = license_msg;
+
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+ while (*p) fprintf(stderr, "%s\n", *p++);
+}
+
+/* ======================================================================== */
+local void version()
+{
+ fprintf(stderr,"%s %s (%s)\n", progname, VERSION, REVDATE);
+
+ fprintf(stderr, "Compilation options: UTIME STDC_HEADERS"
+#ifndef SUPPORT_ZIP
+ " DECOMPRESS_ONLY"
+#endif
+ "\n");
+}
+
+/* ======================================================================== */
+int main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int file_count; /* number of files to precess */
+ int optc; /* current option */
+
+ progname = basename(argv[0]);
+
+ /* Add options in GZIP environment variable if there is one */
+ env = add_envopt(&argc, &argv, OPTIONS_VAR);
+ if (env != NULL) args = argv;
+
+ foreground = sysv_signal(SIGINT, SIG_IGN) != SIG_IGN;
+ if (foreground) {
+ (void) sysv_signal(SIGINT, (sig_type)abort_gzip);
+ }
+#ifdef SIGTERM
+ if (sysv_signal(SIGTERM, SIG_IGN) != SIG_IGN) {
+ (void) sysv_signal(SIGTERM, (sig_type)abort_gzip);
+ }
+#endif
+#ifdef SIGHUP
+ if (sysv_signal(SIGHUP, SIG_IGN) != SIG_IGN) {
+ (void) sysv_signal(SIGHUP, (sig_type)abort_gzip);
+ }
+#endif
+
+#ifndef GNU_STANDARD
+ /* For compatibility with old compress, use program name as an option.
+ * If you compile with -DGNU_STANDARD, this program will behave as
+ * gzip even if it is invoked under the name gunzip or zcat.
+ *
+ * Systems which do not support links can still use -d or -dc.
+ * Ignore an .exe extension for MSDOS, OS/2 and VMS.
+ */
+ if ( strncmp(progname, "un", 2) == 0 /* ungzip, uncompress */
+ || strncmp(progname, "gun", 3) == 0) { /* gunzip */
+ decompress_wanted = 1;
+ }
+ if (strequ(progname+1, "cat") /* zcat, pcat, gcat */
+ || strequ(progname, "gzcat")) { /* gzcat */
+ decompress_wanted = 1;
+ to_stdout = 1;
+ }
+#endif
+
+ strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
+ z_len = strlen(z_suffix);
+
+ while ((optc = getopt(argc, argv, "cdfhH?LmMnNqrS:tvV123456789")) != EOF) {
+ switch (optc) {
+ case 'c':
+ to_stdout = 1; break;
+ case 'd':
+ decompress_wanted = 1;
+ break;
+ case 'f':
+ force++; break;
+ case 'h': case 'H': case '?':
+ help(); do_exit(OK); break;
+ case 'L':
+ license(); do_exit(OK); break;
+ case 'm': /* undocumented, may change later */
+ no_time = 1; break;
+ case 'M': /* undocumented, may change later */
+ no_time = 0; break;
+ case 'n':
+ no_name = no_time = 1; break;
+ case 'N':
+ no_name = no_time = 0; break;
+ case 'q':
+ quiet = 1; verbose = 0; break;
+ case 'S':
+ z_len = strlen(optarg);
+ strcpy(z_suffix, optarg);
+ break;
+ case 't':
+ test = to_stdout = 1;
+ decompress_wanted = 1;
+ break;
+ case 'v':
+ verbose++; quiet = 0; break;
+ case 'V':
+ version(); do_exit(OK); break;
+#ifdef SUPPORT_ZIP
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ level = optc - '0';
+ break;
+#endif
+ default:
+ /* Error message already emitted by getopt_long. */
+ usage();
+ do_exit(ERROR);
+ }
+ } /* loop on all arguments */
+
+#ifndef SUPPORT_ZIP
+ if (!decompress_wanted) {
+ fprintf(stderr, "%s: this version does not support compression\n",
+ progname);
+ do_exit(ERROR);
+ }
+#endif
+
+ /* By default, save name and timestamp on compression but do not
+ * restore them on decompression.
+ */
+ if (no_time < 0) no_time = decompress;
+ if (no_name < 0) no_name = decompress;
+
+ file_count = argc - optind;
+
+ if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX) {
+ fprintf(stderr, "%s: incorrect suffix '%s'\n",
+ progname, optarg);
+ do_exit(ERROR);
+ }
+
+ /* Allocate all global buffers (for DYN_ALLOC option) */
+ ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
+ ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+ ALLOC(ush, d_buf, DIST_BUFSIZE);
+ ALLOC(uch, window, 2L*WSIZE);
+ ALLOC(ush, tab_prefix, 1L<<BITS);
+
+ /* And get to work */
+ if (file_count != 0) {
+ while (optind < argc) {
+ treat_file(argv[optind++]);
+ }
+ } else { /* Standard input */
+ treat_stdin();
+ }
+ do_exit(exit_code);
+ return exit_code; /* just to avoid lint warning */
+}
+
+/* ========================================================================
+ * Compress or decompress stdin
+ */
+local void treat_stdin()
+{
+ if (!force &&
+ isatty(fileno((FILE *)(decompress ? stdin : stdout)))) {
+ /* Do not send compressed data to the terminal or read it from
+ * the terminal. We get here when user invoked the program
+ * without parameters, so be helpful. According to the GNU standards:
+ *
+ * If there is one behavior you think is most useful when the output
+ * is to a terminal, and another that you think is most useful when
+ * the output is a file or a pipe, then it is usually best to make
+ * the default behavior the one that is useful with output to a
+ * terminal, and have an option for the other behavior.
+ *
+ * Here we use the --force option to get the other behavior.
+ */
+ fprintf(stderr,
+ "%s: compressed data not %s a terminal. Use -f to force %scompression.\n",
+ progname, decompress ? "read from" : "written to",
+ decompress ? "de" : "");
+ fprintf(stderr,"For help, type: %s -h\n", progname);
+ do_exit(ERROR);
+ }
+
+ strcpy(ifname, "stdin");
+ strcpy(ofname, "stdout");
+
+ /* Get the time stamp on the input file. */
+ time_stamp = 0; /* time unknown by default */
+
+ if (!no_time) {
+ if (fstat(fileno(stdin), &istat) != 0) {
+ error("fstat(stdin)");
+ }
+ time_stamp = istat.st_mtime;
+ }
+ ifile_size = -1L; /* convention for unknown size */
+
+ clear_bufs(); /* clear input and output buffers */
+ to_stdout = 1;
+ part_nb = 0;
+
+ if (decompress) {
+ method = get_method();
+ if (method < 0) {
+ do_exit(exit_code); /* error message already emitted */
+ }
+ }
+
+ /* Actually do the compression/decompression. Loop over zipped members.
+ */
+ for (;;) {
+ if ((*work)(fileno(stdin), fileno(stdout)) != OK) return;
+
+ if (!decompress || last_member || inptr == insize) break;
+ /* end of file */
+
+ method = get_method();
+ if (method < 0) return; /* error message already emitted */
+ bytes_out = 0; /* required for length check */
+ }
+
+ if (verbose) {
+ if (test) {
+ fprintf(stderr, " OK\n");
+
+ } else if (!decompress) {
+ display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+ fprintf(stderr, "\n");
+#ifdef DISPLAY_STDIN_RATIO
+ } else {
+ display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+ fprintf(stderr, "\n");
+#endif
+ }
+ }
+}
+
+/* ========================================================================
+ * Compress or decompress the given file
+ */
+local void treat_file(iname)
+ char *iname;
+{
+ /* Accept "-" as synonym for stdin */
+ if (strequ(iname, "-")) {
+ int cflag = to_stdout;
+ treat_stdin();
+ to_stdout = cflag;
+ return;
+ }
+
+ /* Check if the input file is present, set ifname and istat: */
+ if (get_istat(iname, &istat) != OK) return;
+
+ /* If the input name is that of a directory, recurse or ignore: */
+ if (S_ISDIR(istat.st_mode)) {
+ WARN((stderr,"%s: %s is a directory -- ignored\n", progname, ifname));
+ return;
+ }
+ if (!S_ISREG(istat.st_mode)) {
+ WARN((stderr,
+ "%s: %s is not a directory or a regular file - ignored\n",
+ progname, ifname));
+ return;
+ }
+ if (istat.st_nlink > 1 && !to_stdout && !force) {
+ WARN((stderr, "%s: %s has %d other link%c -- unchanged\n",
+ progname, ifname,
+ (int)istat.st_nlink - 1, istat.st_nlink > 2 ? 's' : ' '));
+ return;
+ }
+
+ ifile_size = istat.st_size;
+ time_stamp = no_time ? 0 : istat.st_mtime;
+
+ /* Generate output file name. For -r and (-t or -l), skip files
+ * without a valid gzip suffix (check done in make_ofname).
+ */
+ if (to_stdout && !test) {
+ strcpy(ofname, "stdout");
+
+ } else if (make_ofname() != OK) {
+ return;
+ }
+
+ /* Open the input file and determine compression method. The mode
+ * parameter is ignored but required by some systems (VMS) and forbidden
+ * on other systems (MacOS).
+ */
+ ifd = open(ifname, !decompress ? O_RDONLY : O_RDONLY,
+ RW_USER);
+ if (ifd == -1) {
+ fprintf(stderr, "%s: ", progname);
+ perror(ifname);
+ exit_code = ERROR;
+ return;
+ }
+ clear_bufs(); /* clear input and output buffers */
+ part_nb = 0;
+
+ if (decompress) {
+ method = get_method(); /* updates ofname if original given */
+ if (method < 0) {
+ close(ifd);
+ return; /* error message already emitted */
+ }
+ }
+
+ /* If compressing to a file, check if ofname is not ambiguous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ */
+ if (to_stdout) {
+ ofd = fileno(stdout);
+ /* keep remove_ofname as zero */
+ } else {
+ if (create_outfile() != OK) return;
+
+ if (!decompress && save_orig_name && !verbose && !quiet) {
+ fprintf(stderr, "%s: %s compressed to %s\n",
+ progname, ifname, ofname);
+ }
+ }
+ /* Keep the name even if not truncated except with --no-name: */
+ if (!save_orig_name) save_orig_name = !no_name;
+
+ if (verbose) {
+ fprintf(stderr, "%s:\t%s", ifname, (int)strlen(ifname) >= 15 ?
+ "" : ((int)strlen(ifname) >= 7 ? "\t" : "\t\t"));
+ }
+
+ /* Actually do the compression/decompression. Loop over zipped members.
+ */
+ for (;;) {
+ if ((*work)(ifd, ofd) != OK) {
+ method = -1; /* force cleanup */
+ break;
+ }
+ if (!decompress || last_member || inptr == insize) break;
+ /* end of file */
+
+ method = get_method();
+ if (method < 0) break; /* error message already emitted */
+ bytes_out = 0; /* required for length check */
+ }
+
+ close(ifd);
+ if (!to_stdout && close(ofd)) {
+ write_error();
+ }
+ if (method == -1) {
+ if (!to_stdout) unlink (ofname);
+ return;
+ }
+ /* Display statistics */
+ if(verbose) {
+ if (test) {
+ fprintf(stderr, " OK");
+ } else if (decompress) {
+ display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
+ } else {
+ display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
+ }
+ if (!test && !to_stdout) {
+ fprintf(stderr, " -- replaced with %s", ofname);
+ }
+ fprintf(stderr, "\n");
+ }
+ /* Copy modes, times, ownership, and remove the input file */
+ if (!to_stdout) {
+ copy_stat(&istat);
+ }
+}
+
+/* ========================================================================
+ * Create the output file. Return OK or ERROR.
+ * Try several times if necessary to avoid truncating the z_suffix. For
+ * example, do not create a compressed file of name "1234567890123."
+ * Sets save_orig_name to true if the file name has been truncated.
+ * IN assertions: the input file has already been open (ifd is set) and
+ * ofname has already been updated if there was an original name.
+ * OUT assertions: ifd and ofd are closed in case of error.
+ */
+local int create_outfile()
+{
+ struct stat ostat; /* stat for ofname */
+ int flags = O_WRONLY | O_CREAT | O_EXCL;
+
+ for (;;) {
+ /* Make sure that ofname is not an existing file */
+ if (check_ofname() != OK) {
+ close(ifd);
+ return ERROR;
+ }
+ /* Create the output file */
+ remove_ofname = 1;
+ ofd = open(ofname, flags, RW_USER);
+ if (ofd == -1) {
+ perror(ofname);
+ close(ifd);
+ exit_code = ERROR;
+ return ERROR;
+ }
+
+ /* Check for name truncation on new file (1234567890123.gz) */
+ if (fstat(ofd, &ostat) != 0) {
+ fprintf(stderr, "%s: ", progname);
+ perror(ofname);
+ close(ifd); close(ofd);
+ unlink(ofname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ if (!name_too_long(ofname, &ostat)) return OK;
+
+ if (decompress) {
+ /* name might be too long if an original name was saved */
+ WARN((stderr, "%s: %s: warning, name truncated\n",
+ progname, ofname));
+ return OK;
+ }
+ close(ofd);
+ unlink(ofname);
+ shorten_name(ofname);
+ }
+}
+
+/* ========================================================================
+ * Use lstat if available, except for -c or -f. Use stat otherwise.
+ * This allows links when not removing the original file.
+ */
+local int do_stat(name, sbuf)
+ char *name;
+ struct stat *sbuf;
+{
+ errno = 0;
+ if (!to_stdout && !force) {
+ return lstat(name, sbuf);
+ }
+ return stat(name, sbuf);
+}
+
+/* ========================================================================
+ * Return a pointer to the 'z' suffix of a file name, or NULL. For all
+ * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
+ * accepted suffixes, in addition to the value of the --suffix option.
+ * ".tgz" is a useful convention for tar.z files on systems limited
+ * to 3 characters extensions. On such systems, ".?z" and ".??z" are
+ * also accepted suffixes. For Unix, we do not want to accept any
+ * .??z suffix as indicating a compressed file; some people use .xyz
+ * to denote volume data.
+ * On systems allowing multiple versions of the same file (such as VMS),
+ * this function removes any version suffix in the given name.
+ */
+local char *get_suffix(name)
+ char *name;
+{
+ int nlen, slen;
+ char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
+ static char *known_suffixes[] =
+ {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
+ NULL};
+ char **suf = known_suffixes;
+
+ if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
+
+ nlen = strlen(name);
+ if (nlen <= MAX_SUFFIX+2) {
+ strcpy(suffix, name);
+ } else {
+ strcpy(suffix, name+nlen-MAX_SUFFIX-2);
+ }
+ strlwr(suffix);
+ slen = strlen(suffix);
+ do {
+ int s = strlen(*suf);
+ if (slen > s && suffix[slen-s-1] != PATH_SEP
+ && strequ(suffix + slen - s, *suf)) {
+ return name+nlen-s;
+ }
+ } while (*++suf != NULL);
+
+ return NULL;
+}
+
+
+/* ========================================================================
+ * Set ifname to the input file name (with a suffix appended if necessary)
+ * and istat to its stats. For decompression, if no file exists with the
+ * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
+ * For MSDOS, we try only z_suffix and z.
+ * Return OK or ERROR.
+ */
+local int get_istat(iname, sbuf)
+ char *iname;
+ struct stat *sbuf;
+{
+ int ilen; /* strlen(ifname) */
+ static char *suffixes[] = {z_suffix, ".gz", ".z", "-z", ".Z", NULL};
+ char **suf = suffixes;
+ char *s;
+
+ strcpy(ifname, iname);
+
+ /* If input file exists, return OK. */
+ if (do_stat(ifname, sbuf) == 0) return OK;
+
+ if (!decompress || errno != ENOENT) {
+ perror(ifname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ /* file.ext doesn't exist, try adding a suffix (after removing any
+ * version number for VMS).
+ */
+ s = get_suffix(ifname);
+ if (s != NULL) {
+ perror(ifname); /* ifname already has z suffix and does not exist */
+ exit_code = ERROR;
+ return ERROR;
+ }
+ ilen = strlen(ifname);
+ if (strequ(z_suffix, ".gz")) suf++;
+
+ /* Search for all suffixes */
+ do {
+ s = *suf;
+ strcat(ifname, s);
+ if (do_stat(ifname, sbuf) == 0) return OK;
+ ifname[ilen] = '\0';
+ } while (*++suf != NULL);
+
+ /* No suffix found, complain using z_suffix: */
+ strcat(ifname, z_suffix);
+ perror(ifname);
+ exit_code = ERROR;
+ return ERROR;
+}
+
+/* ========================================================================
+ * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
+ * Sets save_orig_name to true if the file name has been truncated.
+ */
+local int make_ofname()
+{
+ char *suff; /* ofname z suffix */
+
+ strcpy(ofname, ifname);
+ /* strip a version number if any and get the gzip suffix if present: */
+ suff = get_suffix(ofname);
+
+ if (decompress) {
+ if (suff == NULL) {
+ /* Whith -t or -l, try all files (even without .gz suffix)
+ * except with -r (behave as with just -dr).
+ */
+ if (test) return OK;
+
+ /* Avoid annoying messages with -r */
+ if (verbose || !quiet) {
+ WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
+ progname, ifname));
+ }
+ return WARNING;
+ }
+ /* Make a special case for .tgz and .taz: */
+ strlwr(suff);
+ if (strequ(suff, ".tgz") || strequ(suff, ".taz")) {
+ strcpy(suff, ".tar");
+ } else {
+ *suff = '\0'; /* strip the z suffix */
+ }
+ /* ofname might be changed later if infile contains an original name */
+
+ } else if (suff != NULL) {
+ /* Avoid annoying messages with -r (see treat_dir()) */
+ if (verbose || !quiet) {
+ fprintf(stderr, "%s: %s already has %s suffix -- unchanged\n",
+ progname, ifname, suff);
+ }
+ if (exit_code == OK) exit_code = WARNING;
+ return WARNING;
+ } else {
+ save_orig_name = 0;
+ strcat(ofname, z_suffix);
+
+ } /* decompress ? */
+ return OK;
+}
+
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * Updates time_stamp if there is one and --no-time is not used.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ * If the member is a zip file, it must be the only one.
+ */
+local int get_method()
+{
+ uch flags; /* compression flags */
+ char magic[2]; /* magic header */
+ ulg stamp; /* time stamp */
+
+ /* If --force and --stdout, zcat == cat, so do not complain about
+ * premature end of file: use try_byte instead of get_byte.
+ */
+ if (force && to_stdout) {
+ magic[0] = (char)try_byte();
+ magic[1] = (char)try_byte();
+ /* If try_byte returned EOF, magic[1] == 0xff */
+ } else {
+ magic[0] = (char)get_byte();
+ magic[1] = (char)get_byte();
+ }
+ method = -1; /* unknown yet */
+ part_nb++; /* number of parts in gzip file */
+ header_bytes = 0;
+ last_member = RECORD_IO;
+ /* assume multiple members in gzip file except for record oriented I/O */
+
+ if (memcmp(magic, GZIP_MAGIC, 2) == 0
+ || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+ method = (int)get_byte();
+ if (method != DEFLATED) {
+ fprintf(stderr,
+ "%s: %s: unknown method %d -- get newer version of gzip\n",
+ progname, ifname, method);
+ exit_code = ERROR;
+ return -1;
+ }
+ work = unzip;
+ flags = (uch)get_byte();
+
+ if ((flags & ENCRYPTED) != 0) {
+ fprintf(stderr,
+ "%s: %s is encrypted -- get newer version of gzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ return -1;
+ }
+ if ((flags & CONTINUATION) != 0) {
+ fprintf(stderr,
+ "%s: %s is a a multi-part gzip file -- get newer version of gzip\n",
+ progname, ifname);
+ exit_code = ERROR;
+ if (force <= 1) return -1;
+ }
+ if ((flags & RESERVED) != 0) {
+ fprintf(stderr,
+ "%s: %s has flags 0x%x -- get newer version of gzip\n",
+ progname, ifname, flags);
+ exit_code = ERROR;
+ if (force <= 1) return -1;
+ }
+ stamp = (ulg)get_byte();
+ stamp |= ((ulg)get_byte()) << 8;
+ stamp |= ((ulg)get_byte()) << 16;
+ stamp |= ((ulg)get_byte()) << 24;
+ if (stamp != 0 && !no_time) time_stamp = stamp;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & CONTINUATION) != 0) {
+ unsigned part = (unsigned)get_byte();
+ part |= ((unsigned)get_byte())<<8;
+ if (verbose) {
+ fprintf(stderr,"%s: %s: part number %u\n",
+ progname, ifname, part);
+ }
+ }
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ if (verbose) {
+ fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
+ progname, ifname, len);
+ }
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ if (no_name || to_stdout || part_nb > 1) {
+ /* Discard the old name */
+ char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
+ do {c=get_byte();} while (c != 0);
+ } else {
+ /* Copy the base name. Keep a directory prefix intact. */
+ char *p = basename(ofname);
+ for (;;) {
+ *p = (char)get_char();
+ if (*p++ == '\0') break;
+ if (p >= ofname+sizeof(ofname)) {
+ error("corrupted input -- file name too large");
+ }
+ }
+ } /* no_name || to_stdout */
+ } /* ORIG_NAME */
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_char() != 0) /* null */ ;
+ }
+ if (part_nb == 1) {
+ header_bytes = inptr + 2*sizeof(long); /* include crc and size */
+ }
+ } else if (force && to_stdout) { /* pass input unchanged */
+ method = STORED;
+ work = copy;
+ inptr = 0;
+ last_member = 1;
+ }
+ if (method >= 0) return method;
+
+ if (part_nb == 1) {
+ fprintf(stderr, "\n%s: %s: not in gzip format\n", progname, ifname);
+ exit_code = ERROR;
+ return -1;
+ } else {
+ WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
+ progname, ifname));
+ return -2;
+ }
+}
+
+
+/* ========================================================================
+ * Return true if the two stat structures correspond to the same file.
+ */
+local int same_file(stat1, stat2)
+ struct stat *stat1;
+ struct stat *stat2;
+{
+ return stat1->st_ino == stat2->st_ino
+ && stat1->st_dev == stat2->st_dev
+#ifdef NO_ST_INO
+ /* Can't rely on st_ino and st_dev, use other fields: */
+ && stat1->st_mode == stat2->st_mode
+ && stat1->st_uid == stat2->st_uid
+ && stat1->st_gid == stat2->st_gid
+ && stat1->st_size == stat2->st_size
+ && stat1->st_atime == stat2->st_atime
+ && stat1->st_mtime == stat2->st_mtime
+ && stat1->st_ctime == stat2->st_ctime
+#endif
+ ;
+}
+
+/* ========================================================================
+ * Return true if a file name is ambiguous because the operating system
+ * truncates file names.
+ */
+local int name_too_long(name, statb)
+ char *name; /* file name to check */
+ struct stat *statb; /* stat buf for this file name */
+{
+ int s = strlen(name);
+ char c = name[s-1];
+ struct stat tstat; /* stat for truncated name */
+ int res;
+
+ tstat = *statb; /* Just in case OS does not fill all fields */
+ name[s-1] = '\0';
+ res = stat(name, &tstat) == 0 && same_file(statb, &tstat);
+ name[s-1] = c;
+ Trace((stderr, " too_long(%s) => %d\n", name, res));
+ return res;
+}
+
+/* ========================================================================
+ * Shorten the given name by one character, or replace a .tar extension
+ * with .tgz. Truncate the last part of the name which is longer than
+ * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
+ * has only parts shorter than MIN_PART truncate the longest part.
+ * For decompression, just remove the last character of the name.
+ *
+ * IN assertion: for compression, the suffix of the given name is z_suffix.
+ */
+local void shorten_name(name)
+ char *name;
+{
+ int len; /* length of name without z_suffix */
+ char *trunc = NULL; /* character to be truncated */
+ int plen; /* current part length */
+ int min_part = MIN_PART; /* current minimum part length */
+ char *p;
+
+ len = strlen(name);
+ if (decompress) {
+ if (len <= 1) error("name too short");
+ name[len-1] = '\0';
+ return;
+ }
+ p = get_suffix(name);
+ if (p == NULL) error("can't recover suffix\n");
+ *p = '\0';
+ save_orig_name = 1;
+
+ /* compress 1234567890.tar to 1234567890.tgz */
+ if (len > 4 && strequ(p-4, ".tar")) {
+ strcpy(p-4, ".tgz");
+ return;
+ }
+ /* Try keeping short extensions intact:
+ * 1234.678.012.gz -> 123.678.012.gz
+ */
+ do {
+ p = strrchr(name, PATH_SEP);
+ p = p ? p+1 : name;
+ while (*p) {
+ plen = strcspn(p, ".");
+ p += plen;
+ if (plen > min_part) trunc = p-1;
+ if (*p) p++;
+ }
+ } while (trunc == NULL && --min_part != 0);
+
+ if (trunc != NULL) {
+ do {
+ trunc[0] = trunc[1];
+ } while (*trunc++);
+ trunc--;
+ } else {
+ trunc = strrchr(name, '.');
+ if (trunc == NULL) error("internal error in shorten_name");
+ if (trunc[1] == '\0') trunc--; /* force truncation */
+ }
+ strcpy(trunc, z_suffix);
+}
+
+/* ========================================================================
+ * If compressing to a file, check if ofname is not ambiguous
+ * because the operating system truncates names. Otherwise, generate
+ * a new ofname and save the original name in the compressed file.
+ * If the compressed file already exists, ask for confirmation.
+ * The check for name truncation is made dynamically, because different
+ * file systems on the same OS might use different truncation rules (on SVR4
+ * s5 truncates to 14 chars and ufs does not truncate).
+ * This function returns -1 if the file must be skipped, and
+ * updates save_orig_name if necessary.
+ * IN assertions: save_orig_name is already set if ofname has been
+ * already truncated because of NO_MULTIPLE_DOTS. The input file has
+ * already been open and istat is set.
+ */
+local int check_ofname()
+{
+ struct stat ostat; /* stat for ofname */
+
+#ifdef ENAMETOOLONG
+ /* Check for strictly conforming Posix systems (which return ENAMETOOLONG
+ * instead of silently truncating filenames).
+ */
+ errno = 0;
+ while (stat(ofname, &ostat) != 0) {
+ if (errno != ENAMETOOLONG) return 0; /* ofname does not exist */
+ shorten_name(ofname);
+ }
+#else
+ if (stat(ofname, &ostat) != 0) return 0;
+#endif
+ /* Check for name truncation on existing file. Do this even on systems
+ * defining ENAMETOOLONG, because on most systems the strict Posix
+ * behavior is disabled by default (silent name truncation allowed).
+ */
+ if (!decompress && name_too_long(ofname, &ostat)) {
+ shorten_name(ofname);
+ if (stat(ofname, &ostat) != 0) return 0;
+ }
+
+ /* Check that the input and output files are different (could be
+ * the same by name truncation or links).
+ */
+ if (same_file(&istat, &ostat)) {
+ if (strequ(ifname, ofname)) {
+ fprintf(stderr, "%s: %s: cannot %scompress onto itself\n",
+ progname, ifname, decompress ? "de" : "");
+ } else {
+ fprintf(stderr, "%s: %s and %s are the same file\n",
+ progname, ifname, ofname);
+ }
+ exit_code = ERROR;
+ return ERROR;
+ }
+ /* Ask permission to overwrite the existing file */
+ if (!force) {
+#if 0
+ char response[80];
+ strcpy(response,"n");
+ fprintf(stderr, "%s: %s already exists;", progname, ofname);
+ if (foreground && isatty(fileno(stdin))) {
+ fprintf(stderr, " do you wish to overwrite (y or n)? ");
+ (void)fgets(response, sizeof(response)-1, stdin);
+ }
+ if (tolow(*response) != 'y') {
+ fprintf(stderr, "\tnot overwritten\n");
+#endif
+ if (exit_code == OK) exit_code = WARNING;
+ return ERROR;
+#if 0
+ }
+#endif
+ }
+ (void) chmod(ofname, 0777);
+ if (unlink(ofname)) {
+ fprintf(stderr, "%s: ", progname);
+ perror(ofname);
+ exit_code = ERROR;
+ return ERROR;
+ }
+ return OK;
+}
+
+
+/* ========================================================================
+ * Set the access and modification times from the given stat buffer.
+ */
+local void reset_times (name, statb)
+ char *name;
+ struct stat *statb;
+{
+ struct utimbuf timep;
+
+ /* Copy the time stamp */
+ timep.actime = statb->st_atime;
+ timep.modtime = statb->st_mtime;
+
+ /* Some systems (at least OS/2) do not support utime on directories */
+ if (utime(name, &timep) && !S_ISDIR(statb->st_mode)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ofname);
+ }
+}
+
+
+/* ========================================================================
+ * Copy modes, times, ownership from input file to output file.
+ * IN assertion: to_stdout is false.
+ */
+local void copy_stat(ifstat)
+ struct stat *ifstat;
+{
+ if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp) {
+ ifstat->st_mtime = time_stamp;
+ if (verbose > 1) {
+ fprintf(stderr, "%s: time stamp restored\n", ofname);
+ }
+ }
+ reset_times(ofname, ifstat);
+
+ /* Copy the protection modes */
+ if (chmod(ofname, ifstat->st_mode & 07777)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ofname);
+ }
+
+ chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
+
+ remove_ofname = 0;
+ /* It's now safe to remove the input file: */
+ (void) chmod(ifname, 0777);
+ if (unlink(ifname)) {
+ WARN((stderr, "%s: ", progname));
+ if (!quiet) perror(ifname);
+ }
+}
+
+/* ========================================================================
+ * Free all dynamically allocated variables and exit with the given code.
+ */
+local void do_exit(exitcode)
+ int exitcode;
+{
+ static int in_exit = 0;
+
+ if (in_exit) exit(exitcode);
+ in_exit = 1;
+ if (env != NULL) free(env), env = NULL;
+ if (args != NULL) free((char*)args), args = NULL;
+ FREE(inbuf);
+ FREE(outbuf);
+ FREE(d_buf);
+ FREE(window);
+ FREE(tab_prefix);
+ exit(exitcode);
+}
+
+/* ========================================================================
+ * Signal and error handler.
+ */
+void abort_gzip()
+{
+ if (remove_ofname) {
+ close(ofd);
+ unlink (ofname);
+ }
+ do_exit(ERROR);
+}
diff --git a/usr/gzip/gzip.h b/usr/gzip/gzip.h
new file mode 100644
index 0000000..7cd2fbd
--- /dev/null
+++ b/usr/gzip/gzip.h
@@ -0,0 +1,298 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+# define OF(args) args
+#else
+# define OF(args) ()
+#endif
+
+#ifdef __STDC__
+ typedef void *voidp;
+#else
+ typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string and io functions are used
+ * too often
+ */
+#include <stdio.h>
+#include <string.h>
+#define memzero(s, n) memset ((voidp)(s), 0, (n))
+
+#define local static
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+/* Return codes from gzip */
+#define OK 0
+#define ERROR 1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED 0
+#define COMPRESSED 1
+#define PACKED 2
+#define LZHED 3
+/* methods 4 to 7 reserved */
+#define DEFLATED 8
+#define MAX_METHODS 9
+extern int method; /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlaid between
+ * the various modules:
+ * deflate: prev+head window d_buf l_buf outbuf
+ * unlzw: tab_prefix tab_suffix stack inbuf outbuf
+ * inflate: window inbuf
+ * unpack: window inbuf prefix_len
+ * unlzh: left+right window c_table inbuf c_len
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef INBUFSIZ
+# ifdef SMALL_MEM
+# define INBUFSIZ 0x2000 /* input buffer size */
+# else
+# define INBUFSIZ 0x8000 /* input buffer size */
+# endif
+#endif
+#define INBUF_EXTRA 64 /* required by unlzw() */
+
+#ifndef OUTBUFSIZ
+# ifdef SMALL_MEM
+# define OUTBUFSIZ 8192 /* output buffer size */
+# else
+# define OUTBUFSIZ 16384 /* output buffer size */
+# endif
+#endif
+#define OUTBUF_EXTRA 2048 /* required by unlzw() */
+
+#ifndef DIST_BUFSIZE
+# ifdef SMALL_MEM
+# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */
+# else
+# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+# endif
+#endif
+
+#ifdef DYN_ALLOC
+# define EXTERN(type, array) extern type * near array
+# define DECLARE(type, array, size) type * near array
+# define ALLOC(type, array, size) { \
+ array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \
+ if (array == NULL) error("insufficient memory"); \
+ }
+# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+# define EXTERN(type, array) extern type array[]
+# define DECLARE(type, array, size) type array[size]
+# define ALLOC(type, array, size)
+# define FREE(array)
+#endif
+
+EXTERN(uch, inbuf); /* input buffer */
+EXTERN(uch, outbuf); /* output buffer */
+EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
+EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+# define tab_prefix prev /* hash link (see deflate.c) */
+# define head (prev+WSIZE) /* hash head (see deflate.c) */
+ EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
+#else
+# define tab_prefix0 prev
+# define head tab_prefix1
+ EXTERN(ush, tab_prefix0); /* prefix for even codes */
+ EXTERN(ush, tab_prefix1); /* prefix for odd codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr; /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in; /* number of input bytes */
+extern long bytes_out; /* number of output bytes */
+extern long header_bytes;/* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int ifd; /* input file descriptor */
+extern int ofd; /* output file descriptor */
+extern char ifname[]; /* input file name or "stdin" */
+extern char ofname[]; /* output file name or "stdout" */
+extern char *progname; /* program name */
+
+extern time_t time_stamp; /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+typedef int file_t; /* Do not use stdio */
+#define NO_FILE (-1) /* in memory compression */
+
+
+#define PACK_MAGIC "\037\036" /* Magic header for packed files */
+#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
+#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files*/
+#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#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 ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/* internal file attribute */
+#define UNKNOWN 0xffff
+#define BINARY 0
+#define ASCII 1
+
+#ifndef WSIZE
+# define WSIZE 0x8000 /* window size--must be a power of two, and */
+#endif /* at least 32K for zip's deflate method */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#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 (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt; /* flag to turn on decryption */
+extern int exit_code; /* program exit code */
+extern int verbose; /* be verbose (-v) */
+extern int quiet; /* be quiet (-q) */
+extern int level; /* compression level */
+extern int test; /* check .z file integrity */
+extern int to_stdout; /* output to stdout (-c) */
+extern int save_orig_name; /* set if original name must be saved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
+#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
+
+/* put_byte is used for the compressed output, put_ubyte for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_ubyte
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+ flush_outbuf();}
+#define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+ flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+ outbuf[outcnt++] = (uch) ((w) & 0xff); \
+ outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+ } else { \
+ put_byte((uch)((w) & 0xff)); \
+ put_byte((uch)((ush)(w) >> 8)); \
+ } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+ put_short((n) & 0xffff); \
+ put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable() 0 /* force sequential output */
+#define translate_eol 0 /* no option -a yet */
+
+#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (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
+
+#define WARN(msg) {if (!quiet) fprintf msg ; \
+ if (exit_code == OK) exit_code = WARNING;}
+
+ /* in zip.c: */
+extern int zip OF((int in, int out));
+extern int file_read OF((char *buf, unsigned size));
+
+ /* in unzip.c */
+extern int unzip OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+ /* in gzip.c */
+void abort_gzip OF((void));
+
+ /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg deflate OF((void));
+
+ /* in trees.c */
+void ct_init OF((ush *attr, int *method));
+int ct_tally OF((int dist, int lc));
+ulg flush_block OF((char *buf, ulg stored_len, int eof));
+
+ /* in bits.c */
+void bi_init OF((file_t zipfile));
+void send_bits OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void bi_windup OF((void));
+void copy_block OF((char *buf, unsigned len, int header));
+extern int (*read_buf) OF((char *buf, unsigned size));
+
+ /* in util.c: */
+extern int copy OF((int in, int out));
+extern ulg updcrc OF((uch *s, unsigned n));
+extern void clear_bufs OF((void));
+extern int fill_inbuf OF((int eof_ok));
+extern void flush_outbuf OF((void));
+extern void flush_window OF((void));
+extern void write_buf OF((int fd, voidp buf, unsigned cnt));
+extern char *strlwr OF((char *s));
+extern char *basename OF((char *fname));
+extern void make_simple_name OF((char *name));
+extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
+extern void error OF((char *m));
+extern void warn OF((char *a, char *b));
+extern void read_error OF((void));
+extern void write_error OF((void));
+extern void display_ratio OF((long num, long den, FILE *file));
+extern voidp xmalloc OF((unsigned int size));
+
+ /* in inflate.c */
+extern int inflate OF((void));
+
+/* stuff from lzw.h */
+#ifndef BITS
+# define BITS 16
+#endif
diff --git a/usr/gzip/inflate.c b/usr/gzip/inflate.c
new file mode 100644
index 0000000..a540538
--- /dev/null
+++ b/usr/gzip/inflate.c
@@ -0,0 +1,950 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/* You can do whatever you like with this source file, though I would
+ prefer that if you modify it and redistribute it that you include
+ comments to that effect with your name and the date. Thank you.
+ [The history has been moved to the file ChangeLog.]
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32K or 64K. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a mutli-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: inflate.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include "tailor.h"
+#include "gzip.h"
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 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};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 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, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 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};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 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};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+ uch cc;
+# define NEXTBYTE() \
+ (decrypt ? (cc = get_byte(), cc) : get_byte())
+#else
+# define NEXTBYTE() (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+int lbits = 9; /* bits in base literal/length lookup table */
+int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+ n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? (unsigned)l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+ return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
diff --git a/usr/gzip/revision.h b/usr/gzip/revision.h
new file mode 100644
index 0000000..736020b
--- /dev/null
+++ b/usr/gzip/revision.h
@@ -0,0 +1,11 @@
+/* revision.h -- define the version number
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#define VERSION "1.2.4"
+#define PATCHLEVEL 0
+#define REVDATE "18 Aug 93"
+
+/* $Id: revision.h,v 1.1 2002/08/18 00:59:21 hpa Exp $ */
diff --git a/usr/gzip/tailor.h b/usr/gzip/tailor.h
new file mode 100644
index 0000000..849e589
--- /dev/null
+++ b/usr/gzip/tailor.h
@@ -0,0 +1,50 @@
+/* tailor.h -- target dependent definitions
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/* The target dependent definitions should be defined here only.
+ * The target dependent functions should be defined in tailor.c.
+ */
+
+/* $Id: tailor.h,v 1.1 2002/08/18 00:59:21 hpa Exp $ */
+
+ /* Common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#define PATH_SEP '/'
+
+#ifndef casemap
+# define casemap(c) (c)
+#endif
+
+#ifndef OPTIONS_VAR
+# define OPTIONS_VAR "GZIP"
+#endif
+
+#ifndef Z_SUFFIX
+# define Z_SUFFIX ".gz"
+#endif
+
+#define MAX_SUFFIX 30
+
+#ifndef MIN_PART
+# define MIN_PART 3
+ /* keep at least MIN_PART chars between dots in a file name. */
+#endif
+
+#ifndef RECORD_IO
+# define RECORD_IO 0
+#endif
+
+#ifndef get_char
+# define get_char() get_byte()
+#endif
+
+#ifndef put_char
+# define put_char(c) put_byte(c)
+#endif
diff --git a/usr/gzip/trees.c b/usr/gzip/trees.c
new file mode 100644
index 0000000..75efc97
--- /dev/null
+++ b/usr/gzip/trees.c
@@ -0,0 +1,1075 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+/*
+ * PURPOSE
+ *
+ * Encode various sets of source values using variable-length
+ * binary code trees.
+ *
+ * DISCUSSION
+ *
+ * The PKZIP "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in the ZIP file 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 UNZIP process, as described in the "application note"
+ * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program.
+ *
+ * REFERENCES
+ *
+ * Lynch, Thomas J.
+ * Data Compression: Techniques and Applications, pp. 53-55.
+ * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7.
+ *
+ * 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.
+ *
+ * INTERFACE
+ *
+ * void ct_init (ush *attr, int *methodp)
+ * Allocate the match buffer, initialize the various tables and save
+ * the location of the internal file attribute (ascii/binary) and
+ * method (DEFLATE/STORE)
+ *
+ * void ct_tally (int dist, int lc);
+ * Save the match info and tally the frequency counts.
+ *
+ * long flush_block (char *buf, ulg stored_len, int eof)
+ * Determine the best encoding for the current block: dynamic trees,
+ * static trees or store, and output the encoded block to the zip
+ * file. Returns the total compressed length for the file so far.
+ *
+ */
+
+#include <ctype.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+#ifdef RCSID
+static char rcsid[] = "$Id: trees.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#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 END_BLOCK 256
+/* end of block literal code */
+
+#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 */
+
+
+local 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 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 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};
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#ifndef LIT_BUFSIZE
+# ifdef SMALL_MEM
+# define LIT_BUFSIZE 0x2000
+# else
+# ifdef MEDIUM_MEM
+# define LIT_BUFSIZE 0x4000
+# else
+# define LIT_BUFSIZE 0x8000
+# endif
+# endif
+#endif
+#ifndef DIST_BUFSIZE
+# define DIST_BUFSIZE LIT_BUFSIZE
+#endif
+/* Sizes of match buffers for literals/lengths and distances. 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).
+ * - 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
+ * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save
+ * memory at the expense of compression). Some optimizations would be possible
+ * if we rely on DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+#if LIT_BUFSIZE > INBUFSIZ
+ error cannot overlay l_buf and inbuf
+#endif
+
+#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 data
+ */
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data {
+ 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;
+} ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+local ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+local ct_data dyn_dtree[2*D_CODES+1]; /* distance tree */
+
+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 ct_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local ct_data bl_tree[2*BL_CODES+1];
+/* Huffman tree for the bit lengths */
+
+typedef struct tree_desc {
+ ct_data *dyn_tree; /* the dynamic tree */
+ ct_data *static_tree; /* corresponding static tree or NULL */
+ int *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 */
+ int max_code; /* largest code with non zero frequency */
+} tree_desc;
+
+local tree_desc l_desc =
+{dyn_ltree, static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS, 0};
+
+local tree_desc d_desc =
+{dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0};
+
+local tree_desc bl_desc =
+{bl_tree, (ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0};
+
+
+local ush bl_count[MAX_BITS+1];
+/* number of codes at each bit length for an optimal tree */
+
+local 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.
+ */
+
+local int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+local int heap_len; /* number of elements in the heap */
+local 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.
+ */
+
+local uch depth[2*L_CODES+1];
+/* Depth of each subtree used as tie breaker for trees of equal frequency */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local uch dist_code[512];
+/* 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.
+ */
+
+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) */
+
+#define l_buf inbuf
+/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */
+
+/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */
+
+local uch flag_buf[(LIT_BUFSIZE/8)];
+/* flag_buf is a bit array distinguishing literals from lengths in
+ * l_buf, thus indicating the presence or absence of a distance.
+ */
+
+local unsigned last_lit; /* running index in l_buf */
+local unsigned last_dist; /* running index in d_buf */
+local unsigned last_flags; /* running index in flag_buf */
+local uch flags; /* current flags not yet saved in flag_buf */
+local uch flag_bit; /* current bit used in flags */
+/* bits are filled in flags starting at bit 0 (least significant).
+ * Note: these flags are overkill in the current code since we don't
+ * take advantage of DIST_BUFSIZE == LIT_BUFSIZE.
+ */
+
+local ulg opt_len; /* bit length of current block with optimal trees */
+local ulg static_len; /* bit length of current block with static trees */
+
+local ulg compressed_len; /* total bit length of compressed file */
+
+local ulg input_len; /* total byte length of input file */
+/* input_len is for debugging only since we can get it by other means. */
+
+ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */
+int *file_method; /* pointer to DEFLATE or STORE */
+
+#ifdef DEBUG
+extern ulg bits_sent; /* bit length of the compressed data */
+extern long isize; /* byte length of input file */
+#endif
+
+extern long block_start; /* window offset of current block */
+extern unsigned strstart; /* window offset of current string */
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void init_block OF((void));
+local void pqdownheap OF((ct_data *tree, int k));
+local void gen_bitlen OF((tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code));
+local void build_tree OF((tree_desc *desc));
+local void scan_tree OF((ct_data *tree, int max_code));
+local void send_tree OF((ct_data *tree, int max_code));
+local int build_bl_tree OF((void));
+local void send_all_trees OF((int lcodes, int dcodes, int blcodes));
+local void compress_block OF((ct_data *ltree, ct_data *dtree));
+local void set_file_type OF((void));
+
+
+#ifndef DEBUG
+# define send_code(c, tree) send_bits(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(c, tree) \
+ { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(tree[c].Code, tree[c].Len); }
+#endif
+
+#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.
+ */
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Allocate the match buffer, initialize the various tables and save the
+ * location of the internal file attribute (ascii/binary) and method
+ * (DEFLATE/STORE).
+ */
+void ct_init(attr, methodp)
+ ush *attr; /* pointer to internal file attribute */
+ int *methodp; /* pointer to compression method */
+{
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+
+ file_type = attr;
+ file_method = methodp;
+ compressed_len = input_len = 0L;
+
+ if (static_dtree[0].Len != 0) return; /* ct_init already called */
+
+ /* 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, "ct_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, "ct_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, "ct_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);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse(n, 5);
+ }
+
+ /* Initialize the first block of the first file: */
+ init_block();
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block()
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0;
+
+ dyn_ltree[END_BLOCK].Freq = 1;
+ opt_len = static_len = 0L;
+ last_lit = last_dist = last_flags = 0;
+ flags = 0; flag_bit = 1;
+}
+
+#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(tree, top) \
+{\
+ top = heap[SMALLEST]; \
+ heap[SMALLEST] = heap[heap_len--]; \
+ pqdownheap(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) \
+ (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(tree, k)
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < heap_len && smaller(tree, heap[j+1], heap[j])) j++;
+
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, heap[j])) break;
+
+ /* Exchange v with the smallest son */
+ heap[k] = heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ 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(desc)
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int *extra = desc->extra_bits;
+ int base = desc->extra_base;
+ int max_code = desc->max_code;
+ int max_length = desc->max_length;
+ ct_data *stree = desc->static_tree;
+ 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++) 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[heap[heap_max]].Len = 0; /* root of the heap */
+
+ for (h = heap_max+1; h < HEAP_SIZE; h++) {
+ n = 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 */
+
+ bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ opt_len += (ulg)f * (bits + xbits);
+ if (stree) 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 (bl_count[bits] == 0) bits--;
+ bl_count[bits]--; /* move one leaf down the tree */
+ bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ 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 = bl_count[bits];
+ while (n != 0) {
+ m = heap[--h];
+ if (m > max_code) continue;
+ if (tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ 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)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+{
+ 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);
+
+ Tracec(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(desc)
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ ct_data *stree = desc->static_tree;
+ int elems = desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node = elems; /* next internal node of the tree */
+
+ /* 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.
+ */
+ heap_len = 0, heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ heap[++heap_len] = max_code = n;
+ 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 (heap_len < 2) {
+ int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0);
+ tree[new].Freq = 1;
+ depth[new] = 0;
+ opt_len--; if (stree) static_len -= stree[new].Len;
+ /* new 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 = heap_len/2; n >= 1; n--) pqdownheap(tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ do {
+ pqremove(tree, n); /* n = node of least frequency */
+ m = heap[SMALLEST]; /* m = node of next least frequency */
+
+ heap[--heap_max] = n; /* keep the nodes sorted by frequency */
+ heap[--heap_max] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ depth[node] = (uch) (MAX(depth[n], depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == 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 */
+ heap[SMALLEST] = node++;
+ pqdownheap(tree, SMALLEST);
+
+ } while (heap_len >= 2);
+
+ heap[--heap_max] = heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen((tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree. Updates opt_len to take into account the repeat
+ * counts. (The contribution of the bit length codes will be added later
+ * during the construction of bl_tree.)
+ */
+local void scan_tree (tree, max_code)
+ 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) {
+ bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) bl_tree[curlen].Freq++;
+ bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ bl_tree[REPZ_3_10].Freq++;
+ } else {
+ 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 (tree, max_code)
+ 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(curlen, bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(curlen, bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(REP_3_6, bl_tree); send_bits(count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3);
+
+ } else {
+ send_code(REPZ_11_138, bl_tree); send_bits(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()
+{
+ 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((ct_data *)dyn_ltree, l_desc.max_code);
+ scan_tree((ct_data *)dyn_dtree, d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree((tree_desc *)(&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 (bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, 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(lcodes, dcodes, blcodes)
+ 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(lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(dcodes-1, 5);
+ send_bits(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(bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", bits_sent));
+
+ send_tree((ct_data *)dyn_ltree, lcodes-1); /* send the literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", bits_sent));
+
+ send_tree((ct_data *)dyn_dtree, dcodes-1); /* send the distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", bits_sent));
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg flush_block(buf, stored_len, eof)
+ char *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; /* index of last bit length code of non zero freq */
+
+ flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */
+
+ /* Check if the file is ascii or binary */
+ if (*file_type == (ush)UNKNOWN) set_file_type();
+
+ /* Construct the literal and distance trees */
+ build_tree((tree_desc *)(&l_desc));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len));
+
+ build_tree((tree_desc *)(&d_desc));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", opt_len, 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();
+
+ /* Determine the best encoding. Compute first the block length in bytes */
+ opt_lenb = (opt_len+3+7)>>3;
+ static_lenb = (static_len+3+7)>>3;
+ input_len += stored_len; /* for debugging only */
+
+ Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
+ opt_lenb, opt_len, static_lenb, static_len, stored_len,
+ last_lit, last_dist));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ /* If compression failed and this is the first and last block,
+ * and if the zip file can be seeked (to rewrite the local header),
+ * the whole file is transformed into a stored file:
+ */
+#ifdef FORCE_METHOD
+ if (level == 1 && eof && compressed_len == 0L) { /* force stored file */
+#else
+ if (stored_len <= opt_lenb && eof && compressed_len == 0L && seekable()) {
+#endif
+ /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+ if (buf == (char*)0) error ("block vanished");
+
+ copy_block(buf, (unsigned)stored_len, 0); /* without header */
+ compressed_len = stored_len << 3;
+ *file_method = STORED;
+
+#ifdef FORCE_METHOD
+ } else if (level == 2 && buf != (char*)0) { /* force stored block */
+#else
+ } 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.
+ */
+ send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
+ compressed_len = (compressed_len + 3 + 7) & ~7L;
+ compressed_len += (stored_len + 4) << 3;
+
+ copy_block(buf, (unsigned)stored_len, 1); /* with header */
+
+#ifdef FORCE_METHOD
+ } else if (level == 3) { /* force static trees */
+#else
+ } else if (static_lenb == opt_lenb) {
+#endif
+ send_bits((STATIC_TREES<<1)+eof, 3);
+ compress_block((ct_data *)static_ltree, (ct_data *)static_dtree);
+ compressed_len += 3 + static_len;
+ } else {
+ send_bits((DYN_TREES<<1)+eof, 3);
+ send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+ compress_block((ct_data *)dyn_ltree, (ct_data *)dyn_dtree);
+ compressed_len += 3 + opt_len;
+ }
+ Assert (compressed_len == bits_sent, "bad compressed size");
+ init_block();
+
+ if (eof) {
+ Assert (input_len == isize, "bad input size");
+ bi_windup();
+ compressed_len += 7; /* align on byte boundary */
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", compressed_len>>3,
+ compressed_len-7*eof));
+
+ return compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ct_tally (dist, lc)
+ int dist; /* distance of matched string */
+ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ l_buf[last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ dyn_ltree[lc].Freq++;
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match");
+
+ dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+ dyn_dtree[d_code(dist)].Freq++;
+
+ d_buf[last_dist++] = (ush)dist;
+ flags |= flag_bit;
+ }
+ flag_bit <<= 1;
+
+ /* Output the flags if they fill a byte: */
+ if ((last_lit & 7) == 0) {
+ flag_buf[last_flags++] = flags;
+ flags = 0, flag_bit = 1;
+ }
+ /* Try to guess if it is profitable to stop the current block here */
+ if (level > 2 && (last_lit & 0xfff) == 0) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)last_lit*8L;
+ ulg in_length = (ulg)strstart-block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
+ last_lit, last_dist, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (last_dist < last_lit/2 && out_length < in_length/2) return 1;
+ }
+ return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE);
+ /* 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(ltree, dtree)
+ 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 dx = 0; /* running index in d_buf */
+ unsigned fx = 0; /* running index in flag_buf */
+ uch flag = 0; /* current flags */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (last_lit != 0) do {
+ if ((lx & 7) == 0) flag = flag_buf[fx++];
+ lc = l_buf[lx++];
+ if ((flag & 1) == 0) {
+ send_code(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(code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(lc, extra); /* send the extra length bits */
+ }
+ dist = d_buf[dx++];
+ /* Here, dist is the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+ flag >>= 1;
+ } while (lx < last_lit);
+
+ send_code(END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Set the file type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_file_type()
+{
+ int n = 0;
+ unsigned ascii_freq = 0;
+ unsigned bin_freq = 0;
+ while (n < 7) bin_freq += dyn_ltree[n++].Freq;
+ while (n < 128) ascii_freq += dyn_ltree[n++].Freq;
+ while (n < LITERALS) bin_freq += dyn_ltree[n++].Freq;
+ *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII;
+ if (*file_type == BINARY && translate_eol) {
+ warn("-l used on binary file", "");
+ }
+}
diff --git a/usr/gzip/unzip.c b/usr/gzip/unzip.c
new file mode 100644
index 0000000..c8e14a3
--- /dev/null
+++ b/usr/gzip/unzip.c
@@ -0,0 +1,77 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+ This version can extract files in gzip format.
+ Only the first entry is extracted, and it has to be
+ either deflated or stored.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: unzip.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include "tailor.h"
+#include "gzip.h"
+
+/* ===========================================================================
+ * Unzip in to out. This routine works on gzip files only.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ * the compressed data, from offsets inptr to insize-1 included.
+ * The magic header has already been checked. The output buffer is cleared.
+ */
+int unzip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int n;
+ uch buf[8]; /* extended local header */
+
+ ifd = in;
+ ofd = out;
+
+ updcrc(NULL, 0); /* initialize crc */
+
+ /* Decompress */
+ if (method == DEFLATED) {
+
+ int res = inflate();
+
+ if (res == 3) {
+ error("out of memory");
+ } else if (res != 0) {
+ error("invalid compressed data--format violated");
+ }
+
+ } else {
+ error("internal error, invalid method");
+ }
+
+ /* Get the crc and original length */
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ for (n = 0; n < 8; n++) {
+ buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+ }
+ orig_crc = LG(buf);
+ orig_len = LG(buf+4);
+
+ /* Validate decompression */
+ if (orig_crc != updcrc(outbuf, 0)) {
+ error("invalid compressed data--crc error");
+ }
+ if (orig_len != (ulg)bytes_out) {
+ error("invalid compressed data--length error");
+ }
+
+ return OK;
+}
diff --git a/usr/gzip/util.c b/usr/gzip/util.c
new file mode 100644
index 0000000..22ff6e5
--- /dev/null
+++ b/usr/gzip/util.c
@@ -0,0 +1,372 @@
+/* util.c -- utility functions for gzip support
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: util.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "tailor.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "gzip.h"
+
+extern ulg crc_32_tab[]; /* crc table, defined below */
+
+/* ===========================================================================
+ * Copy input to output unchanged: zcat == cat with --force.
+ * IN assertion: insize bytes have already been read in inbuf.
+ */
+int copy(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ errno = 0;
+ while (insize != 0 && (int)insize != EOF) {
+ write_buf(out, (char*)inbuf, insize);
+ bytes_out += insize;
+ insize = read(in, (char*)inbuf, INBUFSIZ);
+ }
+ if ((int)insize == EOF && errno != 0) {
+ read_error();
+ }
+ bytes_in = bytes_out;
+ return OK;
+}
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register. If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+ uch *s; /* pointer to bytes to pump through */
+ unsigned n; /* number of bytes in s[] */
+{
+ register ulg c; /* temporary variable */
+
+ static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+ if (s == NULL) {
+ c = 0xffffffffL;
+ } else {
+ c = crc;
+ if (n) do {
+ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+ } while (--n);
+ }
+ crc = c;
+ return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+ outcnt = 0;
+ insize = inptr = 0;
+ bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty.
+ */
+int fill_inbuf(eof_ok)
+ int eof_ok; /* set if EOF acceptable as a result */
+{
+ int len;
+
+ /* Read as much as possible */
+ insize = 0;
+ errno = 0;
+ do {
+ len = read(ifd, (char*)inbuf+insize, INBUFSIZ-insize);
+ if (len == 0 || len == EOF) break;
+ insize += len;
+ } while (insize < INBUFSIZ);
+
+ if (insize == 0) {
+ if (eof_ok) return EOF;
+ read_error();
+ }
+ bytes_in += (ulg)insize;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
+ * (used for the compressed data only)
+ */
+void flush_outbuf()
+{
+ if (outcnt == 0) return;
+
+ write_buf(ofd, (char *)outbuf, outcnt);
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+ if (outcnt == 0) return;
+ updcrc(window, outcnt);
+
+ if (!test) {
+ write_buf(ofd, (char *)window, outcnt);
+ }
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
+}
+
+/* ===========================================================================
+ * Does the same as write(), but also handles partial pipe writes and checks
+ * for error return.
+ */
+void write_buf(fd, buf, cnt)
+ int fd;
+ voidp buf;
+ unsigned cnt;
+{
+ unsigned n;
+
+ while ((n = write(fd, buf, cnt)) != cnt) {
+ if (n == (unsigned)(-1)) {
+ write_error();
+ }
+ cnt -= n;
+ buf = (voidp)((char*)buf+n);
+ }
+}
+
+/* ========================================================================
+ * Put string s in lower case, return s.
+ */
+char *strlwr(s)
+ char *s;
+{
+ char *t;
+ for (t = s; *t; t++) *t = tolow(*t);
+ return s;
+}
+
+/* ========================================================================
+ * Return the base name of a file (remove any directory prefix and
+ * any version suffix). For systems with file names that are not
+ * case sensitive, force the base name to lower case.
+ */
+char *basename(fname)
+ char *fname;
+{
+ char *p;
+
+ if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1;
+ if (casemap('A') == 'a') strlwr(fname);
+ return fname;
+}
+
+/* ========================================================================
+ * Add an environment variable (if any) before argv, and update argc.
+ * Return the expanded environment variable to be freed later, or NULL
+ * if no options were added to argv.
+ */
+#define SEPARATOR " \t" /* separators in env variable */
+
+char *add_envopt(argcp, argvp, env)
+ int *argcp; /* pointer to argc */
+ char ***argvp; /* pointer to argv */
+ char *env; /* name of environment variable */
+{
+ char *p; /* running pointer through env variable */
+ char **oargv; /* runs through old argv array */
+ char **nargv; /* runs through new argv array */
+ int oargc = *argcp; /* old argc */
+ int nargc = 0; /* number of arguments in env variable */
+
+ env = (char*)getenv(env);
+ if (env == NULL) return NULL;
+
+ p = (char*)xmalloc(strlen(env)+1);
+ env = strcpy(p, env); /* keep env variable intact */
+
+ for (p = env; *p; nargc++ ) { /* move through env */
+ p += strspn(p, SEPARATOR); /* skip leading separators */
+ if (*p == '\0') break;
+
+ p += strcspn(p, SEPARATOR); /* find end of word */
+ if (*p) *p++ = '\0'; /* mark it */
+ }
+ if (nargc == 0) {
+ free(env);
+ return NULL;
+ }
+ *argcp += nargc;
+ /* Allocate the new argv array, with an extra element just in case
+ * the original arg list did not end with a NULL.
+ */
+ nargv = (char**)calloc(*argcp+1, sizeof(char *));
+ if (nargv == NULL) error("out of memory");
+ oargv = *argvp;
+ *argvp = nargv;
+
+ /* Copy the program name first */
+ if (oargc-- < 0) error("argc<=0");
+ *(nargv++) = *(oargv++);
+
+ /* Then copy the environment args */
+ for (p = env; nargc > 0; nargc--) {
+ p += strspn(p, SEPARATOR); /* skip separators */
+ *(nargv++) = p; /* store start */
+ while (*p++) ; /* skip over word */
+ }
+
+ /* Finally copy the old args and add a NULL (usual convention) */
+ while (oargc--) *(nargv++) = *(oargv++);
+ *nargv = NULL;
+ return env;
+}
+
+/* ========================================================================
+ * Error handlers.
+ */
+void error(m)
+ char *m;
+{
+ fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
+ abort_gzip();
+}
+
+void warn(a, b)
+ char *a, *b; /* message strings juxtaposed in output */
+{
+ WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
+}
+
+void read_error()
+{
+ fprintf(stderr, "\n%s: ", progname);
+ if (errno != 0) {
+ perror(ifname);
+ } else {
+ fprintf(stderr, "%s: unexpected end of file\n", ifname);
+ }
+ abort_gzip();
+}
+
+void write_error()
+{
+ fprintf(stderr, "\n%s: ", progname);
+ perror(ofname);
+ abort_gzip();
+}
+
+/* ========================================================================
+ * Display compression ratio on the given stream on 6 characters.
+ */
+void display_ratio(num, den, file)
+ long num;
+ long den;
+ FILE *file;
+{
+ long ratio; /* 1000 times the compression ratio */
+ char sign;
+
+ if (den == 0) {
+ ratio = 0; /* no compression */
+ } else if (den < 2147483L) { /* (2**31 -1)/1000 */
+ ratio = 1000L*num/den;
+ } else {
+ ratio = num/(den/1000L);
+ }
+ if (ratio < 0) {
+ sign = '-';
+ ratio = -ratio;
+ } else {
+ sign = ' ';
+ }
+ fprintf(file, "%c%2ld.%1ld%%", sign, ratio / 10L, ratio % 10L);
+}
+
+
+/* ========================================================================
+ * Semi-safe malloc -- never returns NULL.
+ */
+voidp xmalloc (size)
+ unsigned size;
+{
+ voidp cp = (voidp)malloc (size);
+
+ if (cp == NULL) error("out of memory");
+ return cp;
+}
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by makecrc.c)
+ */
+ulg crc_32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
diff --git a/usr/gzip/zip.c b/usr/gzip/zip.c
new file mode 100644
index 0000000..d0394c2
--- /dev/null
+++ b/usr/gzip/zip.c
@@ -0,0 +1,110 @@
+/* zip.c -- compress files to the gzip or pkzip format
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "$Id: zip.c,v 1.1 2002/08/18 00:59:21 hpa Exp $";
+#endif
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "tailor.h"
+#include "gzip.h"
+
+local ulg crc; /* crc on uncompressed file data */
+
+/* ===========================================================================
+ * Deflate in to out.
+ * IN assertions: the input and output buffers are cleared.
+ * The variables time_stamp and save_orig_name are initialized.
+ */
+int zip(in, out)
+ int in, out; /* input and output file descriptors */
+{
+ uch flags = 0; /* general purpose bit flags */
+ ush attr = 0; /* ascii/binary flag */
+ ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
+
+ ifd = in;
+ ofd = out;
+ outcnt = 0;
+
+ /* Write the header to the gzip file. See algorithm.doc for the format */
+
+ method = DEFLATED;
+ put_byte(GZIP_MAGIC[0]); /* magic header */
+ put_byte(GZIP_MAGIC[1]);
+ put_byte(DEFLATED); /* compression method */
+
+ if (save_orig_name) {
+ flags |= ORIG_NAME;
+ }
+ put_byte(flags); /* general flags */
+ put_long(time_stamp);
+
+ /* Write deflated file to zip file */
+ crc = updcrc(0, 0);
+
+ bi_init(out);
+ ct_init(&attr, &method);
+ lm_init(level, &deflate_flags);
+
+ put_byte((uch)deflate_flags); /* extra flags */
+ put_byte(OS_CODE); /* OS identifier */
+
+ if (save_orig_name) {
+ char *p = basename(ifname); /* Don't save the directory part. */
+ do {
+ put_char(*p);
+ } while (*p++);
+ }
+ header_bytes = (long)outcnt;
+
+ (void)deflate();
+
+#if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO)
+ /* Check input size (but not in VMS -- variable record lengths mess it up)
+ * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
+ */
+ if (ifile_size != -1L && isize != (ulg)ifile_size) {
+ Trace((stderr, " actual=%ld, read=%ld ", ifile_size, isize));
+ fprintf(stderr, "%s: %s: file size changed while zipping\n",
+ progname, ifname);
+ }
+#endif
+
+ /* Write the crc and uncompressed size */
+ put_long(crc);
+ put_long(isize);
+ header_bytes += 2*sizeof(long);
+
+ flush_outbuf();
+ return OK;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input file, perform end-of-line
+ * translation, and update the crc and input file size.
+ * IN assertion: size >= 2 (for end-of-line translation)
+ */
+int file_read(buf, size)
+ char *buf;
+ unsigned size;
+{
+ unsigned len;
+
+ Assert(insize == 0, "inbuf not empty");
+
+ len = read(ifd, buf, size);
+ if (len == (unsigned)(-1) || len == 0) return (int)len;
+
+ crc = updcrc((uch*)buf, len);
+ isize += (ulg)len;
+ return (int)len;
+}
diff --git a/usr/include/Kbuild b/usr/include/Kbuild
new file mode 100644
index 0000000..0032724
--- /dev/null
+++ b/usr/include/Kbuild
@@ -0,0 +1,11 @@
+always := asm
+
+$(obj)/asm:
+ @echo ' SYMLINK $@ -> include/asm-$(KLIBCASMARCH)'
+ $(Q)if [ '$(KLIBCKERNELSRC)/.' -ef '$(obj)/../..' ]; then \
+ ln -fsn ../../include/asm-$(KLIBCASMARCH) $@; \
+ else \
+ ln -fsn $(KLIBCKERNELSRC)/include/asm-$(KLIBCASMARCH) $@; \
+ fi
+
+clean-files := asm
diff --git a/usr/include/alloca.h b/usr/include/alloca.h
new file mode 100644
index 0000000..91ef4c0
--- /dev/null
+++ b/usr/include/alloca.h
@@ -0,0 +1,12 @@
+/*
+ * alloca.h
+ *
+ * Just call the builtin alloca() function
+ */
+
+#ifndef _ALLOCA_H
+#define _ALLOCA_H
+
+#define alloca(size) __builtin_alloca(size)
+
+#endif /* _ALLOCA_H */
diff --git a/usr/include/arch/alpha/klibc/archconfig.h b/usr/include/arch/alpha/klibc/archconfig.h
new file mode 100644
index 0000000..6604211
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archconfig.h
@@ -0,0 +1,16 @@
+/*
+ * include/arch/alpha/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* We provide our own restorer that call rt_sigreturn() */
+#define _KLIBC_NEEDS_SA_SIGINFO 1
+#define _KLIBC_STATFS_F_TYPE_64 0
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/alpha/klibc/archsetjmp.h b/usr/include/arch/alpha/klibc/archsetjmp.h
new file mode 100644
index 0000000..47638b3
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsetjmp.h
@@ -0,0 +1,33 @@
+/*
+ * arch/alpha/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __fp;
+ unsigned long __ra;
+ unsigned long __gp;
+ unsigned long __sp;
+
+ unsigned long __f2;
+ unsigned long __f3;
+ unsigned long __f4;
+ unsigned long __f5;
+ unsigned long __f6;
+ unsigned long __f7;
+ unsigned long __f8;
+ unsigned long __f9;
+};
+
+/* Must be an array so it will decay to a pointer when a function is called */
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/alpha/klibc/archsignal.h b/usr/include/arch/alpha/klibc/archsignal.h
new file mode 100644
index 0000000..78be832
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsignal.h
@@ -0,0 +1,88 @@
+/*
+ * arch/alpha/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+/*
+ * This is identical to <asm/signal.h>, *except* for _NSIG and struct
+ * sigaction, where it has the old definition and we need the new (RT)
+ * definition.
+ */
+
+struct siginfo;
+
+#define NSIG 64
+
+typedef unsigned long sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGEMT 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGBUS 10
+#define SIGSEGV 11
+#define SIGSYS 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGURG 16
+#define SIGSTOP 17
+#define SIGTSTP 18
+#define SIGCONT 19
+#define SIGCHLD 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGIO 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGINFO 29
+#define SIGUSR1 30
+#define SIGUSR2 31
+
+#define SIGPOLL SIGIO
+#define SIGPWR SIGINFO
+#define SIGIOT SIGABRT
+
+#define SA_ONSTACK 0x00000001
+#define SA_RESTART 0x00000002
+#define SA_NOCLDSTOP 0x00000004
+#define SA_NODEFER 0x00000008
+#define SA_RESETHAND 0x00000010
+#define SA_NOCLDWAIT 0x00000020
+#define SA_SIGINFO 0x00000040
+
+#define SA_ONESHOT SA_RESETHAND
+#define SA_NOMASK SA_NODEFER
+
+#define MINSIGSTKSZ 4096
+#define SIGSTKSZ 16384
+
+#define SIG_BLOCK 1
+#define SIG_UNBLOCK 2
+#define SIG_SETMASK 3
+
+#include <asm-generic/signal-defs.h>
+
+struct sigaction {
+ union {
+ __sighandler_t sa_handler;
+ void (*sa_sigaction)(int, struct siginfo *, void *);
+ };
+ unsigned long sa_flags;
+ sigset_t sa_mask;
+};
+
+#endif
diff --git a/usr/include/arch/alpha/machine/asm.h b/usr/include/arch/alpha/machine/asm.h
new file mode 100644
index 0000000..c2ae4ed
--- /dev/null
+++ b/usr/include/arch/alpha/machine/asm.h
@@ -0,0 +1,44 @@
+/*
+ * machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/* Standard aliases for Alpha register names */
+
+#define v0 $0
+#define t0 $1
+#define t1 $2
+#define t2 $3
+#define t3 $4
+#define t4 $5
+#define t5 $6
+#define t6 $7
+#define t7 $8
+#define s0 $9
+#define s1 $10
+#define s2 $11
+#define s3 $12
+#define s4 $13
+#define s5 $14
+#define fp $15
+#define a0 $16
+#define a1 $17
+#define a2 $18
+#define a3 $19
+#define a4 $20
+#define a5 $21
+#define t8 $22
+#define t9 $23
+#define t10 $24
+#define t11 $25
+#define ra $26
+#define t12 $27 /* t12 and pv are both used for $27 */
+#define pv $27 /* t12 and pv are both used for $27 */
+#define at $28
+#define gp $29
+#define sp $30
+#define zero $31
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/include/arch/arm/klibc/archconfig.h b/usr/include/arch/arm/klibc/archconfig.h
new file mode 100644
index 0000000..36e9ab5
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archconfig.h
@@ -0,0 +1,18 @@
+/*
+ * include/arch/arm/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* newer arm arch support bx instruction */
+#if (!defined(__ARM_ARCH_2__) && !defined(__ARM_ARCH_3__) \
+ && !defined(__ARM_ARCH_3M__) && !defined(__ARM_ARCH_4__))
+# define _KLIBC_ARM_USE_BX 1
+#endif
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/arm/klibc/archsetjmp.h b/usr/include/arch/arm/klibc/archsetjmp.h
new file mode 100644
index 0000000..88db8a1
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archsetjmp.h
@@ -0,0 +1,14 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned int regs[10];
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/arm/klibc/archsignal.h b/usr/include/arch/arm/klibc/archsignal.h
new file mode 100644
index 0000000..7189da7
--- /dev/null
+++ b/usr/include/arch/arm/klibc/archsignal.h
@@ -0,0 +1,122 @@
+/*
+ * arch/arm/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+/* The in-kernel headers for arm still have libc5
+ crap in them. Reconsider using <asm/signal.h>
+ when/if it gets cleaned up; for now, duplicate
+ the definitions here. */
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/*
+#define SIGLOST 29
+*/
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#define SIGSWI 32
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_SIGINFO deliver the signal with SIGINFO structs
+ * SA_THIRTYTWO delivers the signal in 32-bit mode, even if the task
+ * is running in 26-bit.
+ * SA_ONSTACK allows alternate signal stacks (see sigaltstack(2)).
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP 0x00000001
+#define SA_NOCLDWAIT 0x00000002
+#define SA_SIGINFO 0x00000004
+#define SA_THIRTYTWO 0x02000000
+#define SA_RESTORER 0x04000000
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#include <asm-generic/signal-defs.h>
+
+/* This uses gcc anonymous union support... */
+struct siginfo;
+
+struct sigaction {
+ union {
+ __sighandler_t sa_handler;
+ void (*sa_sigaction)(int, struct siginfo *, void *);
+ };
+ unsigned long sa_flags;
+ __sigrestore_t sa_restorer;
+ sigset_t sa_mask;
+};
+
+#endif
diff --git a/usr/include/arch/arm/klibc/asmmacros.h b/usr/include/arch/arm/klibc/asmmacros.h
new file mode 100644
index 0000000..a6810ce
--- /dev/null
+++ b/usr/include/arch/arm/klibc/asmmacros.h
@@ -0,0 +1,16 @@
+/*
+ * usr/include/arch/arm/klibc/asmmacros.h
+ *
+ * Assembly macros used by ARM system call stubs
+ */
+
+#ifndef _KLIBC_ASMMACROS_H
+#define _KLIBC_ASMMACROS_H
+
+#if _KLIBC_ARM_USE_BX
+# define BX(x) bx x
+#else
+# define BX(x) mov pc, x
+#endif
+
+#endif /* _KLIBC_ASMMACROS_H */
diff --git a/usr/include/arch/arm64/klibc/archconfig.h b/usr/include/arch/arm64/klibc/archconfig.h
new file mode 100644
index 0000000..d094c28
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/arm64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_NO_MMU 0
+#define _KLIBC_REAL_VFORK 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/arm64/klibc/archsetjmp.h b/usr/include/arch/arm64/klibc/archsetjmp.h
new file mode 100644
index 0000000..edc3312
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archsetjmp.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+/*
+ * x19-x28 are callee saved, also save fp, lr, sp.
+ * d8-d15 are unused as we specify -mgeneral-regs-only as a build flag.
+ */
+
+struct __jmp_buf {
+ uint64_t __x19, __x20, __x21, __x22;
+ uint64_t __x23, __x24, __x25, __x26;
+ uint64_t __x27, __x28, __x29, __x30;
+ uint64_t __sp;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/arm64/klibc/archsignal.h b/usr/include/arch/arm64/klibc/archsignal.h
new file mode 100644
index 0000000..94e6bc8
--- /dev/null
+++ b/usr/include/arch/arm64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/arm64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/i386/klibc/archconfig.h b/usr/include/arch/i386/klibc/archconfig.h
new file mode 100644
index 0000000..7d4d5cd
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/i386/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* We have klibc/archinit.h and __libc_archinit() */
+#define _KLIBC_HAS_ARCHINIT 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/i386/klibc/archinit.h b/usr/include/arch/i386/klibc/archinit.h
new file mode 100644
index 0000000..8995ebf
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archinit.h
@@ -0,0 +1,18 @@
+/*
+ * arch/i386/include/klibc/archinit.h
+ *
+ * Architecture-specific libc initialization
+ */
+
+#include <stdint.h>
+#include <klibc/compiler.h>
+#include <elf.h>
+#include <sys/auxv.h>
+
+extern void (*__syscall_entry)(int, ...);
+
+static inline void __libc_archinit(void)
+{
+ if (__auxval[AT_SYSINFO])
+ __syscall_entry = (void (*)(int, ...)) __auxval[AT_SYSINFO];
+}
diff --git a/usr/include/arch/i386/klibc/archsetjmp.h b/usr/include/arch/i386/klibc/archsetjmp.h
new file mode 100644
index 0000000..ea1ba3d
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archsetjmp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned int __ebx;
+ unsigned int __esp;
+ unsigned int __ebp;
+ unsigned int __esi;
+ unsigned int __edi;
+ unsigned int __eip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/i386/klibc/archsignal.h b/usr/include/arch/i386/klibc/archsignal.h
new file mode 100644
index 0000000..5b3379a
--- /dev/null
+++ b/usr/include/arch/i386/klibc/archsignal.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#define SA_RESTORER 0x04000000
+
+#include <asm-generic/signal-defs.h>
+
+struct siginfo;
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+ unsigned int sa_flags;
+ __sigrestore_t sa_restorer;
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/i386/klibc/diverr.h b/usr/include/arch/i386/klibc/diverr.h
new file mode 100644
index 0000000..fa238ac
--- /dev/null
+++ b/usr/include/arch/i386/klibc/diverr.h
@@ -0,0 +1,15 @@
+/*
+ * arch/i386/include/klibc/diverr.h
+ */
+
+#ifndef _KLIBC_DIVERR_H
+#define _KLIBC_DIVERR_H
+
+#include <signal.h>
+
+static __inline__ void __divide_error(void)
+{
+ asm volatile ("int $0");
+}
+
+#endif /* _KLIBC_DIVERR_H */
diff --git a/usr/include/arch/i386/sys/io.h b/usr/include/arch/i386/sys/io.h
new file mode 100644
index 0000000..cf31b97
--- /dev/null
+++ b/usr/include/arch/i386/sys/io.h
@@ -0,0 +1,127 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/io.h for the i386 architecture
+ *
+ * Basic I/O macros
+ */
+
+#ifndef _SYS_IO_H
+#define _SYS_IO_H 1
+
+/* I/O-related system calls */
+
+int iopl(int);
+int ioperm(unsigned long, unsigned long, int);
+
+/* Basic I/O macros */
+
+static __inline__ void outb(unsigned char __v, unsigned short __p)
+{
+ asm volatile ("outb %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ void outw(unsigned short __v, unsigned short __p)
+{
+ asm volatile ("outw %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ void outl(unsigned int __v, unsigned short __p)
+{
+ asm volatile ("outl %0,%1" : : "a" (__v), "dN" (__p));
+}
+
+static __inline__ unsigned char inb(unsigned short __p)
+{
+ unsigned char __v;
+ asm volatile ("inb %1,%0" : "=a" (__v) : "dN" (__p));
+ return __v;
+}
+
+static __inline__ unsigned short inw(unsigned short __p)
+{
+ unsigned short __v;
+ asm volatile ("inw %1,%0" : "=a" (__v) : "dN" (__p));
+ return __v;
+}
+
+static __inline__ unsigned int inl(unsigned short __p)
+{
+ unsigned int __v;
+ asm volatile ("inl %1,%0" : "=a" (__v) : "dN" (__p));
+ return __v;
+}
+
+/* String I/O macros */
+
+static __inline__ void
+outsb(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsb"
+ : "+S" (__d), "+c" (__n)
+ : "d" (__p));
+}
+
+static __inline__ void
+outsw(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsw"
+ : "+S" (__d), "+c" (__n)
+ : "d" (__p));
+}
+
+static __inline__ void
+outsl(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsl"
+ : "+S" (__d), "+c"(__n)
+ : "d" (__p));
+}
+
+static __inline__ void insb(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insb"
+ : "+D" (__d), "+c" (__n)
+ : "d" (__p));
+}
+
+static __inline__ void insw(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insw"
+ : "+D" (__d), "+c" (__n)
+ : "d" (__p));
+}
+
+static __inline__ void insl(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insl"
+ : "+D" (__d), "+c" (__n)
+ : "d" (__p));
+}
+
+#endif /* _SYS_IO_H */
diff --git a/usr/include/arch/i386/sys/vm86.h b/usr/include/arch/i386/sys/vm86.h
new file mode 100644
index 0000000..c4651cd
--- /dev/null
+++ b/usr/include/arch/i386/sys/vm86.h
@@ -0,0 +1,40 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/vm86.h for i386
+ */
+
+#ifndef _SYS_VM86_H
+#define _SYS_VM86_H 1
+
+#include <asm/vm86.h>
+
+/* Actual system call */
+int vm86(struct vm86_struct *);
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archconfig.h b/usr/include/arch/ia64/klibc/archconfig.h
new file mode 100644
index 0000000..9bf3c07
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archconfig.h
@@ -0,0 +1,20 @@
+/*
+ * include/arch/ia64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* IA64 doesn't have sys_fork, but it does have an MMU */
+#define _KLIBC_NO_MMU 0
+/* IA64 doesn't have sys_vfork, it has architecture-specific code */
+#define _KLIBC_REAL_VFORK 1
+/* Need to fix-up function pointers to function descriptor pointers
+ * in struct sigaction */
+#define _KLIBC_NEEDS_SIGACTION_FIXUP 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ia64/klibc/archsetjmp.h b/usr/include/arch/ia64/klibc/archsetjmp.h
new file mode 100644
index 0000000..43564ee
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archsetjmp.h
@@ -0,0 +1,17 @@
+/*
+ * arch/ia64/include/klibc/archsetjmp.h
+ *
+ * Code borrowed from the FreeBSD kernel.
+ *
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+/* User code must not depend on the internal representation of jmp_buf. */
+#define _JBLEN 0x200
+
+/* guaranteed 128-bit alignment! */
+typedef char jmp_buf[_JBLEN] __attribute__ ((aligned(16)));
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archsignal.h b/usr/include/arch/ia64/klibc/archsignal.h
new file mode 100644
index 0000000..7cfbf30
--- /dev/null
+++ b/usr/include/arch/ia64/klibc/archsignal.h
@@ -0,0 +1,32 @@
+/*
+ * arch/ia64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions.
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+#define _NSIG 64
+#define _NSIG_BPW 64
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction) (int, struct siginfo *, void *);
+ } _u;
+ unsigned long sa_flags;
+ sigset_t sa_mask;
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/loongarch64/klibc/archconfig.h b/usr/include/arch/loongarch64/klibc/archconfig.h
new file mode 100644
index 0000000..7a47b91
--- /dev/null
+++ b/usr/include/arch/loongarch64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/loongarch64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* We have an MMU but no fork() syscall */
+#define _KLIBC_NO_MMU 0
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/loongarch64/klibc/archsetjmp.h b/usr/include/arch/loongarch64/klibc/archsetjmp.h
new file mode 100644
index 0000000..939c0f5
--- /dev/null
+++ b/usr/include/arch/loongarch64/klibc/archsetjmp.h
@@ -0,0 +1,26 @@
+/*
+ * include/arch/loongarch64/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __ra;
+ unsigned long __sp;
+ unsigned long __r21;
+ unsigned long __fp;
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __s6;
+ unsigned long __s7;
+ unsigned long __s8;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/loongarch64/klibc/archsignal.h b/usr/include/arch/loongarch64/klibc/archsignal.h
new file mode 100644
index 0000000..c22a5d7
--- /dev/null
+++ b/usr/include/arch/loongarch64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/loongarch64/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/loongarch64/machine/asm.h b/usr/include/arch/loongarch64/machine/asm.h
new file mode 100644
index 0000000..6fe5dba
--- /dev/null
+++ b/usr/include/arch/loongarch64/machine/asm.h
@@ -0,0 +1,24 @@
+/*
+ * include/arch/loongarch64/machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/*
+ * ENTRY - declare entry point
+ */
+#define ENTRY(symbol) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol, @function; \
+symbol:
+
+/*
+ * END - mark end of function
+ */
+#define END(function) \
+ .size function, . - function
+
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/include/arch/m68k/klibc/archconfig.h b/usr/include/arch/m68k/klibc/archconfig.h
new file mode 100644
index 0000000..10ef62e
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/m68k/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* On m68k, sys_mmap2 uses the current page size as the shift factor */
+#define _KLIBC_MMAP2_SHIFT __getpageshift()
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/m68k/klibc/archsetjmp.h b/usr/include/arch/m68k/klibc/archsetjmp.h
new file mode 100644
index 0000000..e85c810
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archsetjmp.h
@@ -0,0 +1,26 @@
+/*
+ * usr/include/arch/m68k/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned int __d2;
+ unsigned int __d3;
+ unsigned int __d4;
+ unsigned int __d5;
+ unsigned int __d6;
+ unsigned int __d7;
+ unsigned int __a2;
+ unsigned int __a3;
+ unsigned int __a4;
+ unsigned int __a5;
+ unsigned int __fp; /* a6 */
+ unsigned int __sp; /* a7 */
+ unsigned int __retaddr;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLBIC_ARCHSETJMP_H */
diff --git a/usr/include/arch/m68k/klibc/archsignal.h b/usr/include/arch/m68k/klibc/archsignal.h
new file mode 100644
index 0000000..6461346
--- /dev/null
+++ b/usr/include/arch/m68k/klibc/archsignal.h
@@ -0,0 +1,74 @@
+/*
+ * arch/m68k/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#include <asm-generic/signal-defs.h>
+
+struct siginfo;
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+ unsigned int sa_flags;
+ __sigrestore_t sa_restorer;
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/mips/klibc/archconfig.h b/usr/include/arch/mips/klibc/archconfig.h
new file mode 100644
index 0000000..ff0afb5
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archconfig.h
@@ -0,0 +1,21 @@
+/*
+ * include/arch/mips/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* MIPS has architecture-specific code for vfork() */
+#define _KLIBC_REAL_VFORK 1
+
+/* MIPS defines it's own statfs */
+#define _KLIBC_STATFS_F_TYPE_32B 1
+
+/* MIPS has nonstandard socket definitions */
+#define _KLIBC_HAS_ARCHSOCKET_H 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/mips/klibc/archfcntl.h b/usr/include/arch/mips/klibc/archfcntl.h
new file mode 100644
index 0000000..586afb4
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archfcntl.h
@@ -0,0 +1,107 @@
+/*
+ * arch/mips/include/klibc/archfcntl.h
+ *
+ * On MIPS, <asm/fcntl.h> isn't usable (compiling struct stat with
+ * the correct definitions doesn't "just work"), so we need to provide
+ * our own definitions.
+ */
+
+#ifndef _KLIBC_ARCHFCNTL_H
+#define _KLIBC_ARCHFCNTL_H
+
+#ifdef _ASM_FCNTL_H /* We were too late! */
+# error "<asm/fcntl.h> included before <klibc/archfcntl.h>"
+#endif
+#define _ASM_FCNTL_H /* Keep <asm/fcntl.h> from getting included */
+
+#define O_ACCMODE 0x0003
+#define O_RDONLY 0x0000
+#define O_WRONLY 0x0001
+#define O_RDWR 0x0002
+#define O_APPEND 0x0008
+#define O_NONBLOCK 0x0080
+#define O_CREAT 0x0100
+#define O_TRUNC 0x0200
+#define O_EXCL 0x0400
+#define O_NOCTTY 0x0800
+#define FASYNC 0x1000
+#define O_LARGEFILE 0x2000
+#define O_SYNC 0x4010
+#define O_DIRECT 0x8000
+#define O_DIRECTORY 0x10000
+#define O_NOFOLLOW 0x20000
+#define O_NOATIME 0x40000
+#define O_CLOEXEC 0x80000
+#define O_PATH 0x200000
+#define O_TMPFILE 0x410000
+
+#define O_NDELAY O_NONBLOCK
+
+#define F_DUPFD 0
+#define F_GETFD 1
+#define F_SETFD 2
+#define F_GETFL 3
+#define F_SETFL 4
+#define F_GETLK 14
+#define F_SETLK 6
+#define F_SETLKW 7
+
+#define F_SETOWN 24
+#define F_GETOWN 23
+#define F_SETSIG 10
+#define F_GETSIG 11
+
+#define F_GETLK64 33
+#define F_SETLK64 34
+#define F_SETLKW64 35
+
+#define F_SETOWN_EX 15
+#define F_GETOWN_EX 16
+
+#define F_GETOWNER_UIDS 17
+
+#define F_OFD_GETLK 36
+#define F_OFD_SETLK 37
+#define F_OFD_SETLKW 38
+
+#define F_OWNER_TID 0
+#define F_OWNER_PID 1
+#define F_OWNER_PGRP 2
+
+struct f_owner_ex {
+ int type;
+ pid_t pid;
+};
+
+#define FD_CLOEXEC 1
+
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+#define F_EXLCK 4
+#define F_SHLCK 8
+
+#define F_INPROGRESS 16
+
+#define LOCK_SH 1
+#define LOCK_EX 2
+#define LOCK_NB 4
+#define LOCK_UN 8
+
+#define LOCK_MAND 32
+#define LOCK_READ 64
+#define LOCK_WRITE 128
+#define LOCK_RW 192
+
+typedef struct flock {
+ short l_type;
+ short l_whence;
+ loff_t l_start;
+ loff_t l_len;
+ pid_t l_pid;
+} flock_t;
+
+#define F_LINUX_SPECIFIC_BASE 1024
+
+#endif /* _KLIBC_ARCHFCNTL_H */
diff --git a/usr/include/arch/mips/klibc/archsetjmp.h b/usr/include/arch/mips/klibc/archsetjmp.h
new file mode 100644
index 0000000..eeadffc
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsetjmp.h
@@ -0,0 +1,25 @@
+/*
+ * arch/mips/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __s6;
+ unsigned long __s7;
+ unsigned long __gp;
+ unsigned long __sp;
+ unsigned long __s8;
+ unsigned long __ra;
+} __attribute__ ((aligned(8)));
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/mips/klibc/archsignal.h b/usr/include/arch/mips/klibc/archsignal.h
new file mode 100644
index 0000000..b9ca756
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/mips/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/mips/klibc/archsocket.h b/usr/include/arch/mips/klibc/archsocket.h
new file mode 100644
index 0000000..d6daf1b
--- /dev/null
+++ b/usr/include/arch/mips/klibc/archsocket.h
@@ -0,0 +1,17 @@
+/*
+ * arch/mips/klibc/archsocket.h
+ */
+
+#ifndef _KLIBC_ARCHSOCKET_H
+#define _KLIBC_ARCHSOCKET_H
+
+#ifndef SOCK_STREAM
+# define SOCK_DGRAM 1
+# define SOCK_STREAM 2
+# define SOCK_RAW 3
+# define SOCK_RDM 4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET 10
+#endif
+
+#endif /* _KLIBC_ARCHSOCKET_H */
diff --git a/usr/include/arch/mips/machine/asm.h b/usr/include/arch/mips/machine/asm.h
new file mode 100644
index 0000000..0b8cece
--- /dev/null
+++ b/usr/include/arch/mips/machine/asm.h
@@ -0,0 +1,76 @@
+/*
+ * arch/mips/include/machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/*
+ * Symbolic register names for 32 bit ABI
+ */
+
+#define zero $0 /* wired zero */
+#define AT $1 /* assembler temp - uppercase because of ".set at" */
+#define v0 $2 /* return value */
+#define v1 $3
+#define a0 $4 /* argument registers */
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define t0 $8 /* caller saved */
+#define t1 $9
+#define t2 $10
+#define t3 $11
+#define t4 $12
+#define t5 $13
+#define t6 $14
+#define t7 $15
+#define s0 $16 /* callee saved */
+#define s1 $17
+#define s2 $18
+#define s3 $19
+#define s4 $20
+#define s5 $21
+#define s6 $22
+#define s7 $23
+#define t8 $24 /* caller saved */
+#define t9 $25
+#define jp $25 /* PIC jump register */
+#define k0 $26 /* kernel scratch */
+#define k1 $27
+#define gp $28 /* global pointer */
+#define sp $29 /* stack pointer */
+#define fp $30 /* frame pointer */
+#define s8 $30 /* same like fp! */
+#define ra $31 /* return address */
+
+/*
+ * LEAF - declare leaf routine
+ */
+#define LEAF(symbol) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol,@function; \
+ .ent symbol,0; \
+symbol: .frame sp,0,ra
+
+
+/*
+ * NESTED - declare nested routine entry point
+ */
+#define NESTED(symbol, framesize, rpc) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol,@function; \
+ .ent symbol,0; \
+symbol: .frame sp, framesize, rpc
+
+/*
+ * END - mark end of function
+ */
+#define END(function) \
+ .end function; \
+ .size function,.-function
+
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/include/arch/mips/sgidefs.h b/usr/include/arch/mips/sgidefs.h
new file mode 100644
index 0000000..fba8ae8
--- /dev/null
+++ b/usr/include/arch/mips/sgidefs.h
@@ -0,0 +1,20 @@
+/*
+ * arch/mips/include/sgidefs.h
+ */
+
+/* Some ABI constants */
+
+#ifndef _SGIDEFS_H
+#define _SGIDEFS_H
+
+#define _MIPS_ISA_MIPS1 1
+#define _MIPS_ISA_MIPS2 2
+#define _MIPS_ISA_MIPS3 3
+#define _MIPS_ISA_MIPS4 4
+#define _MIPS_ISA_MIPS5 5
+
+#define _MIPS_SIM_ABI32 1
+#define _MIPS_SIM_NABI32 2
+#define _MIPS_SIM_ABI64 3
+
+#endif /* _SGIDEFS_H */
diff --git a/usr/include/arch/mips/spaces.h b/usr/include/arch/mips/spaces.h
new file mode 100644
index 0000000..b5f530b
--- /dev/null
+++ b/usr/include/arch/mips/spaces.h
@@ -0,0 +1 @@
+/* Included by <asm/page.h> but not actually needed */
diff --git a/usr/include/arch/mips64/klibc/archconfig.h b/usr/include/arch/mips64/klibc/archconfig.h
new file mode 100644
index 0000000..fa31482
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archconfig.h
@@ -0,0 +1,20 @@
+/*
+ * include/arch/mips64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* MIPS has nonstandard socket definitions */
+#define _KLIBC_HAS_ARCHSOCKET_H 1
+
+#define _KLIBC_STATFS_F_TYPE_64 1
+
+/* MIPS has architecture-specific code for vfork() */
+#define _KLIBC_REAL_VFORK 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/mips64/klibc/archsetjmp.h b/usr/include/arch/mips64/klibc/archsetjmp.h
new file mode 100644
index 0000000..bfca777
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archsetjmp.h
@@ -0,0 +1,25 @@
+/*
+ * arch/mips64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __s6;
+ unsigned long __s7;
+ unsigned long __gp;
+ unsigned long __sp;
+ unsigned long __s8;
+ unsigned long __ra;
+} __attribute__ ((aligned(8)));
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/mips64/klibc/archsignal.h b/usr/include/arch/mips64/klibc/archsignal.h
new file mode 100644
index 0000000..f350af9
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/mips64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/mips64/klibc/archsocket.h b/usr/include/arch/mips64/klibc/archsocket.h
new file mode 100644
index 0000000..6c3947d
--- /dev/null
+++ b/usr/include/arch/mips64/klibc/archsocket.h
@@ -0,0 +1,17 @@
+/*
+ * arch/mips64/klibc/archsocket.h
+ */
+
+#ifndef _KLIBC_ARCHSOCKET_H
+#define _KLIBC_ARCHSOCKET_H
+
+#ifndef SOCK_STREAM
+# define SOCK_DGRAM 1
+# define SOCK_STREAM 2
+# define SOCK_RAW 3
+# define SOCK_RDM 4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET 10
+#endif
+
+#endif /* _KLIBC_ARCHSOCKET_H */
diff --git a/usr/include/arch/mips64/machine/asm.h b/usr/include/arch/mips64/machine/asm.h
new file mode 100644
index 0000000..42dcaa4
--- /dev/null
+++ b/usr/include/arch/mips64/machine/asm.h
@@ -0,0 +1,82 @@
+/*
+ * arch/mips64/include/machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/*
+ * Symbolic register names for 64 bit ABI
+ */
+
+
+#define zero $0 /* wired zero */
+#define AT $at /* assembler temp - uppercase because of ".set at" */
+#define v0 $2 /* return value - caller saved */
+#define v1 $3
+#define a0 $4 /* argument registers */
+#define a1 $5
+#define a2 $6
+#define a3 $7
+#define a4 $8 /* arg reg 64 bit; caller saved in 32 bit */
+#define ta0 $8
+#define a5 $9
+#define ta1 $9
+#define a6 $10
+#define ta2 $10
+#define a7 $11
+#define ta3 $11
+#define t4 $12 /* caller saved */
+#define t5 $13
+#define t6 $14
+#define t7 $15
+#define s0 $16 /* callee saved */
+#define s1 $17
+#define s2 $18
+#define s3 $19
+#define s4 $20
+#define s5 $21
+#define s6 $22
+#define s7 $23
+#define t8 $24 /* caller saved */
+#define t9 $25 /* callee address for PIC/temp */
+#define jp $25 /* PIC jump register */
+#define k0 $26 /* kernel temporary */
+#define k1 $27
+#define gp $28 /* global pointer - caller saved for PIC */
+#define sp $29 /* stack pointer */
+#define fp $30 /* frame pointer */
+#define s8 $30 /* callee saved */
+#define ra $31 /* return address */
+
+
+/*
+ * LEAF - declare leaf routine
+ */
+#define LEAF(symbol) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol,@function; \
+ .ent symbol,0; \
+symbol: .frame sp,0,ra
+
+
+/*
+ * NESTED - declare nested routine entry point
+ */
+#define NESTED(symbol, framesize, rpc) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol,@function; \
+ .ent symbol,0; \
+symbol: .frame sp, framesize, rpc
+
+/*
+ * END - mark end of function
+ */
+#define END(function) \
+ .end function; \
+ .size function,.-function
+
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/include/arch/parisc/klibc/archconfig.h b/usr/include/arch/parisc/klibc/archconfig.h
new file mode 100644
index 0000000..f8ba9e2
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archconfig.h
@@ -0,0 +1,14 @@
+/*
+ * include/arch/parisc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* All defaults */
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/parisc/klibc/archsetjmp.h b/usr/include/arch/parisc/klibc/archsetjmp.h
new file mode 100644
index 0000000..05e943e
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archsetjmp.h
@@ -0,0 +1,14 @@
+/*
+ * arch/parisc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ double regs[21];
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/parisc/klibc/archsignal.h b/usr/include/arch/parisc/klibc/archsignal.h
new file mode 100644
index 0000000..256aeea
--- /dev/null
+++ b/usr/include/arch/parisc/klibc/archsignal.h
@@ -0,0 +1,25 @@
+/*
+ * arch/parisc/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+#define _NSIG 64
+#define _NSIG_SZ (_NSIG / LONG_BIT)
+
+typedef struct {
+ unsigned long sig[_NSIG_SZ];
+} sigset_t;
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ unsigned long sa_flags;
+ sigset_t sa_mask;
+};
+
+#endif
diff --git a/usr/include/arch/ppc/klibc/archconfig.h b/usr/include/arch/ppc/klibc/archconfig.h
new file mode 100644
index 0000000..584af21
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archconfig.h
@@ -0,0 +1,12 @@
+/*
+ * include/arch/ppc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ppc/klibc/archsetjmp.h b/usr/include/arch/ppc/klibc/archsetjmp.h
new file mode 100644
index 0000000..4be9ed6
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archsetjmp.h
@@ -0,0 +1,36 @@
+/*
+ * arch/ppc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __r2;
+ unsigned long __sp;
+ unsigned long __lr;
+ unsigned long __cr;
+ unsigned long __r13;
+ unsigned long __r14;
+ unsigned long __r15;
+ unsigned long __r16;
+ unsigned long __r17;
+ unsigned long __r18;
+ unsigned long __r19;
+ unsigned long __r20;
+ unsigned long __r21;
+ unsigned long __r22;
+ unsigned long __r23;
+ unsigned long __r24;
+ unsigned long __r25;
+ unsigned long __r26;
+ unsigned long __r27;
+ unsigned long __r28;
+ unsigned long __r29;
+ unsigned long __r30;
+ unsigned long __r31;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/ppc/klibc/archsignal.h b/usr/include/arch/ppc/klibc/archsignal.h
new file mode 100644
index 0000000..9c3ac92
--- /dev/null
+++ b/usr/include/arch/ppc/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/ppc64/klibc/archconfig.h b/usr/include/arch/ppc64/klibc/archconfig.h
new file mode 100644
index 0000000..61b61f4
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archconfig.h
@@ -0,0 +1,10 @@
+/*
+ * include/arch/ppc64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in this file.
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/ppc64/klibc/archsetjmp.h b/usr/include/arch/ppc64/klibc/archsetjmp.h
new file mode 100644
index 0000000..d227728
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archsetjmp.h
@@ -0,0 +1,36 @@
+/*
+ * arch/ppc64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __r2;
+ unsigned long __sp;
+ unsigned long __lr;
+ unsigned long __cr;
+ unsigned long __r13;
+ unsigned long __r14;
+ unsigned long __r15;
+ unsigned long __r16;
+ unsigned long __r17;
+ unsigned long __r18;
+ unsigned long __r19;
+ unsigned long __r20;
+ unsigned long __r21;
+ unsigned long __r22;
+ unsigned long __r23;
+ unsigned long __r24;
+ unsigned long __r25;
+ unsigned long __r26;
+ unsigned long __r27;
+ unsigned long __r28;
+ unsigned long __r29;
+ unsigned long __r30;
+ unsigned long __r31;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/ppc64/klibc/archsignal.h b/usr/include/arch/ppc64/klibc/archsignal.h
new file mode 100644
index 0000000..2c4cef0
--- /dev/null
+++ b/usr/include/arch/ppc64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/riscv64/klibc/archconfig.h b/usr/include/arch/riscv64/klibc/archconfig.h
new file mode 100644
index 0000000..e85a69c
--- /dev/null
+++ b/usr/include/arch/riscv64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/riscv64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* We have an MMU but no fork() syscall */
+#define _KLIBC_NO_MMU 0
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/riscv64/klibc/archsetjmp.h b/usr/include/arch/riscv64/klibc/archsetjmp.h
new file mode 100644
index 0000000..97d6b6b
--- /dev/null
+++ b/usr/include/arch/riscv64/klibc/archsetjmp.h
@@ -0,0 +1,27 @@
+/*
+ * arch/riscv64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __pc;
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __s6;
+ unsigned long __s7;
+ unsigned long __s8;
+ unsigned long __s9;
+ unsigned long __s10;
+ unsigned long __s11;
+ unsigned long __sp;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/riscv64/klibc/archsignal.h b/usr/include/arch/riscv64/klibc/archsignal.h
new file mode 100644
index 0000000..560a951
--- /dev/null
+++ b/usr/include/arch/riscv64/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/riscv/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/riscv64/machine/asm.h b/usr/include/arch/riscv64/machine/asm.h
new file mode 100644
index 0000000..9effc93
--- /dev/null
+++ b/usr/include/arch/riscv64/machine/asm.h
@@ -0,0 +1,26 @@
+/*
+ * arch/riscv64/include/machine/asm.h
+ *
+ * Mostly cribbed from mips.
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/*
+ * ENTRY - declare entry point
+ */
+#define ENTRY(symbol) \
+ .globl symbol; \
+ .align 2; \
+ .type symbol, @function; \
+symbol:
+
+/*
+ * END - mark end of function
+ */
+#define END(function) \
+ .size function, . - function
+
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/include/arch/s390/klibc/archconfig.h b/usr/include/arch/s390/klibc/archconfig.h
new file mode 100644
index 0000000..b08bbb3
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archconfig.h
@@ -0,0 +1,20 @@
+/*
+ * include/arch/s390/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* Both s390 and s390x use the "32-bit" version of this structure */
+#define _KLIBC_STATFS_F_TYPE_64 0
+
+/* So that we can avoid stack trampolines */
+#define _KLIBC_NEEDS_SA_RESTORER 1
+/* Our restorer will call rt_sigreturn() */
+#define _KLIBC_NEEDS_SA_SIGINFO 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/s390/klibc/archsetjmp.h b/usr/include/arch/s390/klibc/archsetjmp.h
new file mode 100644
index 0000000..1167c8b
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archsetjmp.h
@@ -0,0 +1,26 @@
+/*
+ * arch/s390/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+#ifndef __s390x__
+
+struct __jmp_buf {
+ uint32_t __gregs[10]; /* general registers r6-r15 */
+ uint64_t __fpregs[2]; /* fp registers f4 and f6 */
+};
+
+#else /* __s390x__ */
+
+struct __jmp_buf {
+ uint64_t __gregs[10]; /* general registers r6-r15 */
+ uint64_t __fpregs[8]; /* fp registers f8-f15 */
+};
+
+#endif /* __s390x__ */
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/s390/klibc/archsignal.h b/usr/include/arch/s390/klibc/archsignal.h
new file mode 100644
index 0000000..31993a4
--- /dev/null
+++ b/usr/include/arch/s390/klibc/archsignal.h
@@ -0,0 +1,76 @@
+/*
+ * arch/s390/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define _NSIG 64
+#define _NSIG_BPW __BITS_PER_LONG
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#define SA_RESTORER 0x04000000
+
+#include <asm-generic/signal-defs.h>
+
+struct siginfo;
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ sigset_t sa_mask;
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/sh/klibc/archconfig.h b/usr/include/arch/sh/klibc/archconfig.h
new file mode 100644
index 0000000..1f1f4a7
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archconfig.h
@@ -0,0 +1,12 @@
+/*
+ * include/arch/sh/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sh/klibc/archsetjmp.h b/usr/include/arch/sh/klibc/archsetjmp.h
new file mode 100644
index 0000000..bb97167
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archsetjmp.h
@@ -0,0 +1,22 @@
+/*
+ * arch/sh/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __r8;
+ unsigned long __r9;
+ unsigned long __r10;
+ unsigned long __r11;
+ unsigned long __r12;
+ unsigned long __r13;
+ unsigned long __r14;
+ unsigned long __r15;
+ unsigned long __pr;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/sh/klibc/archsignal.h b/usr/include/arch/sh/klibc/archsignal.h
new file mode 100644
index 0000000..8e48e51
--- /dev/null
+++ b/usr/include/arch/sh/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/sh/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/sparc/klibc/archconfig.h b/usr/include/arch/sparc/klibc/archconfig.h
new file mode 100644
index 0000000..bdc8b1e
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archconfig.h
@@ -0,0 +1,19 @@
+/*
+ * include/arch/sparc/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_SYS_SOCKETCALL 1 /* Use sys_socketcall unconditionally */
+
+/* So that we can avoid stack trampolines */
+#define _KLIBC_NEEDS_SA_RESTORER 1
+/* Our restorer will call rt_sigreturn() */
+#define _KLIBC_NEEDS_SA_SIGINFO 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sparc/klibc/archsetjmp.h b/usr/include/arch/sparc/klibc/archsetjmp.h
new file mode 100644
index 0000000..9b4d6a2
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archsetjmp.h
@@ -0,0 +1,16 @@
+/*
+ * arch/sparc/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __sp;
+ unsigned long __fp;
+ unsigned long __pc;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/sparc/klibc/archsignal.h b/usr/include/arch/sparc/klibc/archsignal.h
new file mode 100644
index 0000000..b0de544
--- /dev/null
+++ b/usr/include/arch/sparc/klibc/archsignal.h
@@ -0,0 +1,17 @@
+/*
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define __WANT_POSIX1B_SIGNALS__
+
+#include <linux/signal.h>
+
+/* Not actually used by the kernel... */
+#define SA_RESTORER 0x80000000
+
+#endif
diff --git a/usr/include/arch/sparc/machine/asm.h b/usr/include/arch/sparc/machine/asm.h
new file mode 100644
index 0000000..fd9ef1e
--- /dev/null
+++ b/usr/include/arch/sparc/machine/asm.h
@@ -0,0 +1,202 @@
+/* $NetBSD: asm.h,v 1.14 2002/07/20 08:37:30 mrg Exp $ */
+
+/*
+ * Copyright (c) 1994 Allen Briggs
+ * All rights reserved.
+ *
+ * Gleaned from locore.s and sun3 asm.h which had the following copyrights:
+ * locore.s:
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * sun3/include/asm.h:
+ * Copyright (c) 1993 Adam Glass
+ * Copyright (c) 1990 The Regents of the University of California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 _ASM_H_
+#define _ASM_H_
+
+/* Pull in CCFSZ, CC64FSZ, and BIAS from frame.h */
+#ifndef _LOCORE
+#define _LOCORE
+#endif
+#include <machine/frame.h>
+
+#ifdef __ELF__
+#define _C_LABEL(name) name
+#else
+#ifdef __STDC__
+#define _C_LABEL(name) _ ## name
+#else
+#define _C_LABEL(name) _/**/name
+#endif
+#endif
+#define _ASM_LABEL(name) name
+
+#ifdef __PIC__
+/*
+ * PIC_PROLOGUE() is akin to the compiler generated function prologue for
+ * PIC code. It leaves the address of the Global Offset Table in DEST,
+ * clobbering register TMP in the process.
+ *
+ * We can use two code sequences. We can read the %pc or use the call
+ * instruction that saves the pc in %o7. Call requires the branch unit and
+ * IEU1, and clobbers %o7 which needs to be restored. This instruction
+ * sequence takes about 4 cycles due to instruction interdependence. Reading
+ * the pc takes 4 cycles to dispatch and is always dispatched alone. That
+ * sequence takes 7 cycles.
+ */
+#ifdef __arch64__
+#define PIC_PROLOGUE(dest,tmp) \
+ mov %o7, tmp; \
+ sethi %hi(_GLOBAL_OFFSET_TABLE_-4),dest; \
+ call 0f; \
+ or dest,%lo(_GLOBAL_OFFSET_TABLE_+4),dest; \
+0: \
+ add dest,%o7,dest; \
+ mov tmp, %o7
+#define SET(var,base,dest) \
+ sethi %gdop_hix22(var), dest; \
+ xor dest, %gdop_lox10(var), dest; \
+ ldx [base + dest], dest, %gdop(var)
+#else
+#define PIC_PROLOGUE(dest,tmp) \
+ mov %o7,tmp; 3: call 4f; nop; 4: \
+ sethi %hi(_C_LABEL(_GLOBAL_OFFSET_TABLE_)-(3b-.)),dest; \
+ or dest,%lo(_C_LABEL(_GLOBAL_OFFSET_TABLE_)-(3b-.)),dest; \
+ add dest,%o7,dest; mov tmp,%o7
+#define SET(var,base,dest) \
+ sethi %gdop_hix22(var), dest; \
+ xor dest, %gdop_lox10(var), dest; \
+ ld [base + dest], dest, %gdop(var)
+#endif
+
+/*
+ * PICCY_SET() does the equivalent of a `set var, %dest' instruction in
+ * a PIC-like way, but without involving the Global Offset Table. This
+ * only works for VARs defined in the same file *and* in the text segment.
+ */
+#ifdef __arch64__
+#define PICCY_SET(var,dest,tmp) \
+ 3: rd %pc, tmp; add tmp,(var-3b),dest
+#else
+#define PICCY_SET(var,dest,tmp) \
+ mov %o7,tmp; 3: call 4f; nop; 4: \
+ add %o7,(var-3b),dest; mov tmp,%o7
+#endif
+#else
+#define PIC_PROLOGUE(dest,tmp)
+#define SET(var,base,dest) \
+ sethi %hi(var), dest; \
+ or dest, %lo(var), dest
+#define PICCY_SET(var,dest,tmp) SET(var,tmp,dest)
+#endif
+
+#define FTYPE(x) .type x,@function
+#define OTYPE(x) .type x,@object
+
+#define _ENTRY(name) \
+ .align 4; .globl name; .proc 1; FTYPE(name); name:
+
+#ifdef GPROF
+/* see _MCOUNT_ENTRY in profile.h */
+#ifdef __ELF__
+#ifdef __arch64__
+#define _PROF_PROLOGUE \
+ .data; .align 8; 1: .uaword 0; .uaword 0; \
+ .text; save %sp,-CC64FSZ,%sp; sethi %hi(1b),%o0; call _mcount; \
+ or %o0,%lo(1b),%o0; restore
+#else
+#define _PROF_PROLOGUE \
+ .data; .align 4; 1: .long 0; \
+ .text; save %sp,-96,%sp; sethi %hi(1b),%o0; call _mcount; \
+ or %o0,%lo(1b),%o0; restore
+#endif
+#else
+#ifdef __arch64__
+#define _PROF_PROLOGUE \
+ .data; .align 8; 1: .uaword 0; .uaword 0; \
+ .text; save %sp,-CC64FSZ,%sp; sethi %hi(1b),%o0; call mcount; \
+ or %o0,%lo(1b),%o0; restore
+#else
+#define _PROF_PROLOGUE \
+ .data; .align 4; 1: .long 0; \
+ .text; save %sp,-96,%sp; sethi %hi(1b),%o0; call mcount; \
+ or %o0,%lo(1b),%o0; restore
+#endif
+#endif
+#else
+#define _PROF_PROLOGUE
+#endif
+
+#define ENTRY(name) _ENTRY(_C_LABEL(name)); _PROF_PROLOGUE
+#define ENTRY_NOPROFILE(name) _ENTRY(_C_LABEL(name))
+#define ASENTRY(name) _ENTRY(_ASM_LABEL(name)); _PROF_PROLOGUE
+#define FUNC(name) ASENTRY(name)
+#define RODATA(name) .align 4; .text; .globl _C_LABEL(name); \
+ OTYPE(_C_LABEL(name)); _C_LABEL(name):
+
+#define ASMSTR .asciz
+
+#define RCSID(name) .asciz name
+
+#ifdef __ELF__
+#define WEAK_ALIAS(alias,sym) \
+ .weak alias; \
+ alias = sym
+#endif
+
+/*
+ * WARN_REFERENCES: create a warning if the specified symbol is referenced.
+ */
+#ifdef __ELF__
+#ifdef __STDC__
+#define WARN_REFERENCES(_sym,_msg) \
+ .section .gnu.warning. ## _sym ; .ascii _msg ; .text
+#else
+#define WARN_REFERENCES(_sym,_msg) \
+ .section .gnu.warning./**/_sym ; .ascii _msg ; .text
+#endif /* __STDC__ */
+#else
+#ifdef __STDC__
+#define __STRING(x) #x
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg ## ,30,0,0,0 ; \
+ .stabs __STRING(_ ## sym) ## ,1,0,0,0
+#else
+#define __STRING(x) "x"
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg,30,0,0,0 ; \
+ .stabs __STRING(_/**/sym),1,0,0,0
+#endif /* __STDC__ */
+#endif /* __ELF__ */
+
+#endif /* _ASM_H_ */
diff --git a/usr/include/arch/sparc/machine/frame.h b/usr/include/arch/sparc/machine/frame.h
new file mode 100644
index 0000000..6fb9c45
--- /dev/null
+++ b/usr/include/arch/sparc/machine/frame.h
@@ -0,0 +1,146 @@
+/* $NetBSD: frame.h,v 1.4 2001/12/04 00:05:05 darrenr Exp $ */
+
+/*
+ * 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.
+ *
+ * @(#)frame.h 8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef _MACHINE_FRAME_H
+#define _MACHINE_FRAME_H
+
+#ifdef __ASSEMBLY__
+# define _LOCORE
+#endif
+
+#ifndef _LOCORE
+# include <stdint.h>
+#endif
+
+/*
+ * Sparc stack frame format.
+ *
+ * Note that the contents of each stack frame may be held only in
+ * machine register windows. In order to get an accurate picture
+ * of the frame, you must first force the kernel to write any such
+ * windows to the stack.
+ */
+#ifndef _LOCORE
+#ifndef SUN4U
+struct frame {
+ int32_t fr_local[8]; /* space to save locals (%l0..%l7) */
+ int32_t fr_arg[6]; /* space to save arguments (%i0..%i5) */
+ struct frame *fr_fp; /* space to save frame pointer (%i6) */
+ int32_t fr_pc; /* space to save return pc (%i7) */
+ /*
+ * SunOS reserves another 8 words here; this is pointless
+ * but we do it for compatibility.
+ */
+ int32_t fr_xxx; /* `structure return pointer' (unused) */
+ int32_t fr_argd[6]; /* `arg dump area' (lunacy) */
+ int32_t fr_argx[1]; /* arg extension (args 7..n; variable size) */
+};
+#else
+struct frame32 {
+ int32_t fr_local[8]; /* space to save locals (%l0..%l7) */
+ int32_t fr_arg[6]; /* space to save arguments (%i0..%i5) */
+ uint32_t fr_fp; /* space to save frame pointer (%i6) */
+ uint32_t fr_pc; /* space to save return pc (%i7) */
+ /*
+ * SunOS reserves another 8 words here; this is pointless
+ * but we do it for compatibility.
+ */
+ int32_t fr_xxx; /* `structure return pointer' (unused) */
+ int32_t fr_argd[6]; /* `arg dump area' (lunacy) */
+ int32_t fr_argx[1]; /* arg extension (args 7..n; variable size) */
+};
+#endif
+#endif
+
+/*
+ * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
+ * a function is to call C code. It should be just 64, but Sun defined
+ * their frame with space to hold arguments 0 through 5 (plus some junk),
+ * and varargs routines (such as kprintf) demand this, and gcc uses this
+ * area at times anyway.
+ */
+#define CCFSZ 96
+
+/*
+ * Sparc v9 stack frame format.
+ *
+ * Note that the contents of each stack frame may be held only in
+ * machine register windows. In order to get an accurate picture
+ * of the frame, you must first force the kernel to write any such
+ * windows to the stack.
+ *
+ * V9 frames have an odd bias, so you can tall a v9 frame from
+ * a v8 frame by testing the stack pointer's lsb.
+ */
+#if !defined(_LOCORE) && !defined(_LIBC)
+struct frame64 {
+ int64_t fr_local[8]; /* space to save locals (%l0..%l7) */
+ int64_t fr_arg[6]; /* space to save arguments (%i0..%i5) */
+ uint64_t fr_fp; /* space to save frame pointer (%i6) */
+ uint64_t fr_pc; /* space to save return pc (%i7) */
+ /*
+ * SVR4 reserves a bunch of extra stuff.
+ */
+ int64_t fr_argd[6]; /* `register save area' (lunacy) */
+ int64_t fr_argx[0]; /* arg extension (args 7..n; variable size) */
+};
+
+#define v9next_frame(f) ((struct frame64*)(f->fr_fp+BIAS))
+#endif
+
+/*
+ * CC64FSZ (C Compiler 64-bit Frame SiZe) is the size of a stack frame used
+ * by the compiler in 64-bit mode. It is (16)*8; space for 8 ins, 8 outs.
+ */
+#define CC64FSZ 176
+
+/*
+ * v9 stacks all have a bias of 2047 added to the %sp and %fp, so you can easily
+ * detect it by testing the register for an odd value. Why 2K-1 I don't know.
+ */
+#define BIAS (2048-1)
+
+#endif /* _MACHINE_FRAME_H */
diff --git a/usr/include/arch/sparc/machine/trap.h b/usr/include/arch/sparc/machine/trap.h
new file mode 100644
index 0000000..5c378c5
--- /dev/null
+++ b/usr/include/arch/sparc/machine/trap.h
@@ -0,0 +1,140 @@
+/* $NetBSD: trap.h,v 1.11 1999/01/20 00:15:08 pk Exp $ */
+
+/*
+ * 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.
+ *
+ * @(#)trap.h 8.1 (Berkeley) 6/11/93
+ */
+/*
+ * Sun4m support by Aaron Brown, Harvard University.
+ * Changes Copyright (c) 1995 The President and Fellows of Harvard College.
+ * All rights reserved.
+ */
+
+#ifndef _MACHINE_TRAP_H
+#define _MACHINE_TRAP_H
+
+/* trap vec (pri) description */
+#define T_RESET 0x00 /* (1) not actually vectored; jumps to 0 */
+#define T_TEXTFAULT 0x01 /* (2) address fault during instr fetch */
+#define T_ILLINST 0x02 /* (3) illegal instruction */
+#define T_PRIVINST 0x03 /* (4) privileged instruction */
+#define T_FPDISABLED 0x04 /* (5) fp instr while fp disabled */
+#define T_WINOF 0x05 /* (6) register window overflow */
+#define T_WINUF 0x06 /* (7) register window underflow */
+#define T_ALIGN 0x07 /* (8) address not properly aligned */
+#define T_FPE 0x08 /* (9) floating point exception */
+#define T_DATAFAULT 0x09 /* (10) address fault during data fetch */
+#define T_TAGOF 0x0a /* (11) tag overflow */
+/* 0x0b unused */
+/* 0x0c unused */
+/* 0x0d unused */
+/* 0x0e unused */
+/* 0x0f unused */
+/* 0x10 unused */
+#define T_L1INT 0x11 /* (27) level 1 interrupt */
+#define T_L2INT 0x12 /* (26) level 2 interrupt */
+#define T_L3INT 0x13 /* (25) level 3 interrupt */
+#define T_L4INT 0x14 /* (24) level 4 interrupt */
+#define T_L5INT 0x15 /* (23) level 5 interrupt */
+#define T_L6INT 0x16 /* (22) level 6 interrupt */
+#define T_L7INT 0x17 /* (21) level 7 interrupt */
+#define T_L8INT 0x18 /* (20) level 8 interrupt */
+#define T_L9INT 0x19 /* (19) level 9 interrupt */
+#define T_L10INT 0x1a /* (18) level 10 interrupt */
+#define T_L11INT 0x1b /* (17) level 11 interrupt */
+#define T_L12INT 0x1c /* (16) level 12 interrupt */
+#define T_L13INT 0x1d /* (15) level 13 interrupt */
+#define T_L14INT 0x1e /* (14) level 14 interrupt */
+#define T_L15INT 0x1f /* (13) level 15 interrupt */
+/* 0x20 unused */
+/* through 0x23 unused */
+#define T_CPDISABLED 0x24 /* (5) coprocessor instr while disabled */
+#define T_UNIMPLFLUSH 0x25 /* Unimplemented FLUSH */
+/* through 0x27 unused */
+#define T_CPEXCEPTION 0x28 /* (9) coprocessor exception */
+/* 0x29 unused */
+#define T_IDIV0 0x2a /* divide by zero (from hw [su]div instr) */
+#define T_STOREBUFFAULT 0x2b /* SuperSPARC: Store buffer copy-back fault */
+/* 0x2c unused */
+/* through 0x7f unused */
+
+/* beginning of `user' vectors (from trap instructions) - all priority 12 */
+#define T_SUN_SYSCALL 0x80 /* system call */
+#define T_BREAKPOINT 0x81 /* breakpoint `instruction' */
+#define T_DIV0 0x82 /* division routine was handed 0 */
+#define T_FLUSHWIN 0x83 /* flush windows */
+#define T_CLEANWIN 0x84 /* provide clean windows */
+#define T_RANGECHECK 0x85 /* ? */
+#define T_FIXALIGN 0x86 /* fix up unaligned accesses */
+#define T_INTOF 0x87 /* integer overflow ? */
+#define T_SVR4_SYSCALL 0x88 /* SVR4 system call */
+#define T_BSD_SYSCALL 0x89 /* BSD system call */
+#define T_KGDB_EXEC 0x8a /* for kernel gdb */
+
+/* 0x8b..0xff are currently unallocated, except the following */
+#define T_SVR4_GETCC 0xa0
+#define T_SVR4_SETCC 0xa1
+#define T_SVR4_GETPSR 0xa2
+#define T_SVR4_SETPSR 0xa3
+#define T_SVR4_GETHRTIME 0xa4
+#define T_SVR4_GETHRVTIME 0xa5
+#define T_SVR4_GETHRESTIME 0xa7
+
+#ifdef _KERNEL /* pseudo traps for locore.s */
+#define T_RWRET -1 /* need first user window for trap return */
+#define T_AST -2 /* no-op, just needed reschedule or profile */
+#endif
+
+/* flags to system call (flags in %g1 along with syscall number) */
+#define SYSCALL_G2RFLAG 0x400 /* on success, return to %g2 rather than npc */
+#define SYSCALL_G7RFLAG 0x800 /* use %g7 as above (deprecated) */
+
+/*
+ * `software trap' macros to keep people happy (sparc v8 manual says not
+ * to set the upper bits).
+ */
+#define ST_BREAKPOINT (T_BREAKPOINT & 0x7f)
+#define ST_DIV0 (T_DIV0 & 0x7f)
+#define ST_FLUSHWIN (T_FLUSHWIN & 0x7f)
+#define ST_SYSCALL (T_SUN_SYSCALL & 0x7f)
+
+#endif /* _MACHINE_TRAP_H_ */
diff --git a/usr/include/arch/sparc64/klibc/archconfig.h b/usr/include/arch/sparc64/klibc/archconfig.h
new file mode 100644
index 0000000..df5c806
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/sparc64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+#define _KLIBC_NEEDS_SA_RESTORER 1 /* Need a restorer function */
+#define _KLIBC_SYS_SOCKETCALL 1 /* Use sys_socketcall unconditionally */
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/sparc64/klibc/archsetjmp.h b/usr/include/arch/sparc64/klibc/archsetjmp.h
new file mode 100644
index 0000000..9e825bd
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archsetjmp.h
@@ -0,0 +1,16 @@
+/*
+ * arch/sparc64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __sp;
+ unsigned long __fp;
+ unsigned long __pc;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/sparc64/klibc/archsignal.h b/usr/include/arch/sparc64/klibc/archsignal.h
new file mode 100644
index 0000000..bb0a5ce
--- /dev/null
+++ b/usr/include/arch/sparc64/klibc/archsignal.h
@@ -0,0 +1,17 @@
+/*
+ * arch/sparc64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define __WANT_POSIX1B_SIGNALS__
+#include <asm/signal.h>
+
+/* Not actually used by the kernel... */
+#define SA_RESTORER 0x80000000
+
+#endif
diff --git a/usr/include/arch/sparc64/machine/asm.h b/usr/include/arch/sparc64/machine/asm.h
new file mode 100644
index 0000000..394ba86
--- /dev/null
+++ b/usr/include/arch/sparc64/machine/asm.h
@@ -0,0 +1 @@
+#include "../../sparc/machine/asm.h"
diff --git a/usr/include/arch/sparc64/machine/frame.h b/usr/include/arch/sparc64/machine/frame.h
new file mode 100644
index 0000000..79beea6
--- /dev/null
+++ b/usr/include/arch/sparc64/machine/frame.h
@@ -0,0 +1 @@
+#include "../../sparc/machine/frame.h"
diff --git a/usr/include/arch/x86_64/klibc/archconfig.h b/usr/include/arch/x86_64/klibc/archconfig.h
new file mode 100644
index 0000000..b8a2a6d
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/x86_64/klibc/archconfig.h
+ *
+ * See include/klibc/sysconfig.h for the options that can be set in
+ * this file.
+ *
+ */
+
+#ifndef _KLIBC_ARCHCONFIG_H
+#define _KLIBC_ARCHCONFIG_H
+
+/* x86-64 doesn't provide a default sigreturn. */
+#define _KLIBC_NEEDS_SA_RESTORER 1
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/x86_64/klibc/archsetjmp.h b/usr/include/arch/x86_64/klibc/archsetjmp.h
new file mode 100644
index 0000000..454fc60
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archsetjmp.h
@@ -0,0 +1,21 @@
+/*
+ * arch/x86_64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __rbx;
+ unsigned long __rsp;
+ unsigned long __rbp;
+ unsigned long __r12;
+ unsigned long __r13;
+ unsigned long __r14;
+ unsigned long __r15;
+ unsigned long __rip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/arch/x86_64/klibc/archsignal.h b/usr/include/arch/x86_64/klibc/archsignal.h
new file mode 100644
index 0000000..d68ab82
--- /dev/null
+++ b/usr/include/arch/x86_64/klibc/archsignal.h
@@ -0,0 +1,64 @@
+/*
+ * arch/x86_64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#define _NSIG 64
+#define NSIG _NSIG
+typedef unsigned long sigset_t;
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#define SA_RESTORER 0x04000000
+
+#include <asm-generic/signal-defs.h>
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ unsigned long sa_flags;
+ __sigrestore_t sa_restorer;
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+#endif
diff --git a/usr/include/arch/x86_64/sys/io.h b/usr/include/arch/x86_64/sys/io.h
new file mode 100644
index 0000000..19ea1fc
--- /dev/null
+++ b/usr/include/arch/x86_64/sys/io.h
@@ -0,0 +1,127 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/io.h for the i386 architecture
+ *
+ * Basic I/O macros
+ */
+
+#ifndef _SYS_IO_H
+#define _SYS_IO_H 1
+
+/* I/O-related system calls */
+
+int iopl(int);
+int ioperm(unsigned long, unsigned long, int);
+
+/* Basic I/O macros */
+
+static __inline__ void outb(unsigned char __v, unsigned short __p)
+{
+ asm volatile ("outb %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ void outw(unsigned short __v, unsigned short __p)
+{
+ asm volatile ("outw %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ void outl(unsigned int __v, unsigned short __p)
+{
+ asm volatile ("outl %0,%1" : : "a" (__v), "dN"(__p));
+}
+
+static __inline__ unsigned char inb(unsigned short __p)
+{
+ unsigned char __v;
+ asm volatile ("inb %1,%0" : "=a" (__v) : "dN"(__p));
+ return __v;
+}
+
+static __inline__ unsigned short inw(unsigned short __p)
+{
+ unsigned short __v;
+ asm volatile ("inw %1,%0" : "=a" (__v) : "dN"(__p));
+ return __v;
+}
+
+static __inline__ unsigned int inl(unsigned short __p)
+{
+ unsigned int __v;
+ asm volatile ("inl %1,%0" : "=a" (__v) : "dN"(__p));
+ return __v;
+}
+
+/* String I/O macros */
+
+static __inline__ void
+outsb(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsb"
+ : "+S" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+static __inline__ void
+outsw(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsw"
+ : "+S" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+static __inline__ void
+outsl(unsigned short __p, const void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; outsl"
+ : "+S" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+static __inline__ void insb(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insb"
+ : "+D" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+static __inline__ void insw(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insw"
+ : "+D" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+static __inline__ void insl(unsigned short __p, void *__d, unsigned long __n)
+{
+ asm volatile ("cld; rep; insl"
+ : "+D" (__d), "+c"(__n)
+ : "d"(__p));
+}
+
+#endif /* _SYS_IO_H */
diff --git a/usr/include/arpa/inet.h b/usr/include/arpa/inet.h
new file mode 100644
index 0000000..8532f67
--- /dev/null
+++ b/usr/include/arpa/inet.h
@@ -0,0 +1,22 @@
+/*
+ * arpa/inet.h
+ */
+
+#ifndef _ARPA_INET_H
+#define _ARPA_INET_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/in6.h>
+
+__extern uint32_t inet_addr(const char *);
+__extern int inet_aton(const char *, struct in_addr *);
+__extern char *inet_ntoa(struct in_addr);
+__extern int inet_pton(int, const char *, void *);
+__extern const char *inet_ntop(int, const void *, char *, size_t);
+__extern unsigned int inet_nsap_addr(const char *, unsigned char *, int);
+__extern char *inet_nsap_ntoa(int, const unsigned char *, char *);
+
+#endif /* _ARPA_INET_H */
diff --git a/usr/include/assert.h b/usr/include/assert.h
new file mode 100644
index 0000000..9091733
--- /dev/null
+++ b/usr/include/assert.h
@@ -0,0 +1,28 @@
+/*
+ * assert.h
+ */
+
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+#include <klibc/compiler.h>
+
+#ifdef NDEBUG
+
+/*
+ * NDEBUG doesn't just suppress the faulting behavior of assert(),
+ * but also all side effects of the assert() argument. This behavior
+ * is required by the C standard, and allows the argument to reference
+ * variables that are not defined without NDEBUG.
+ */
+#define assert(x) ((void)(0))
+
+#else
+
+extern __noreturn __assert_fail(const char *, const char *, unsigned int);
+
+#define assert(x) ((x) ? (void)0 : __assert_fail(#x, __FILE__, __LINE__))
+
+#endif
+
+#endif /* _ASSERT_H */
diff --git a/usr/include/bits32/bitsize.h b/usr/include/bits32/bitsize.h
new file mode 100644
index 0000000..06cc885
--- /dev/null
+++ b/usr/include/bits32/bitsize.h
@@ -0,0 +1,3 @@
+#ifndef _BITSIZE
+#define _BITSIZE 32
+#endif
diff --git a/usr/include/bits32/bitsize/limits.h b/usr/include/bits32/bitsize/limits.h
new file mode 100644
index 0000000..8eb97d6
--- /dev/null
+++ b/usr/include/bits32/bitsize/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits32/limits.h
+ */
+
+#ifndef _BITSIZE_LIMITS_H
+#define _BITSIZE_LIMITS_H
+
+#define LONG_BIT 32
+
+#define LONG_MIN (-2147483647L-1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 4294967295UL
+
+#endif /* _BITSIZE_LIMITS_H */
diff --git a/usr/include/bits32/bitsize/stdint.h b/usr/include/bits32/bitsize/stdint.h
new file mode 100644
index 0000000..8e444b6
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdint.h
@@ -0,0 +1,34 @@
+/*
+ * bits32/stdint.h
+ */
+
+#ifndef _BITSIZE_STDINT_H
+#define _BITSIZE_STDINT_H
+
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long long int int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+
+typedef int int_fast16_t;
+typedef int int_fast32_t;
+
+typedef unsigned int uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+
+#define __INT64_C(c) c ## LL
+#define __UINT64_C(c) c ## ULL
+
+#define __PRI64_RANK "ll"
+#define __PRIFAST_RANK ""
+#define __PRIPTR_RANK ""
+
+#endif /* _BITSIZE_STDINT_H */
diff --git a/usr/include/bits32/bitsize/stdintconst.h b/usr/include/bits32/bitsize/stdintconst.h
new file mode 100644
index 0000000..7db63bd
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdintconst.h
@@ -0,0 +1,18 @@
+/*
+ * bits32/stdintconst.h
+ */
+
+#ifndef _BITSIZE_STDINTCONST_H
+#define _BITSIZE_STDINTCONST_H
+
+#define INT_FAST16_C(c) INT32_C(c)
+#define INT_FAST32_C(c) INT32_C(c)
+
+#define UINT_FAST16_C(c) UINT32_C(c)
+#define UINT_FAST32_C(c) UINT32_C(c)
+
+#define INTPTR_C(c) INT32_C(c)
+#define UINTPTR_C(c) UINT32_C(c)
+#define PTRDIFF_C(c) INT32_C(c)
+
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/usr/include/bits32/bitsize/stdintlimits.h b/usr/include/bits32/bitsize/stdintlimits.h
new file mode 100644
index 0000000..4c1c2e6
--- /dev/null
+++ b/usr/include/bits32/bitsize/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits32/stdintlimits.h
+ */
+
+#ifndef _BITSIZE_STDINTLIMITS_H
+#define _BITSIZE_STDINTLIMITS_H
+
+#define INT_FAST16_MIN INT32_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST16_MAX INT32_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+#define SIZE_MAX UINT32_MAX
+
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/bits64/bitsize.h b/usr/include/bits64/bitsize.h
new file mode 100644
index 0000000..54696fd
--- /dev/null
+++ b/usr/include/bits64/bitsize.h
@@ -0,0 +1,3 @@
+#ifndef _BITSIZE
+#define _BITSIZE 64
+#endif
diff --git a/usr/include/bits64/bitsize/limits.h b/usr/include/bits64/bitsize/limits.h
new file mode 100644
index 0000000..f5bbf83
--- /dev/null
+++ b/usr/include/bits64/bitsize/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits64/limits.h
+ */
+
+#ifndef _BITSIZE_LIMITS_H
+#define _BITSIZE_LIMITS_H
+
+#define LONG_BIT 64
+
+#define LONG_MIN (-9223372036854775807L-1)
+#define LONG_MAX 9223372036854775807L
+#define ULONG_MAX 18446744073709551615UL
+
+#endif /* _BITSIZE_LIMITS_H */
diff --git a/usr/include/bits64/bitsize/stdint.h b/usr/include/bits64/bitsize/stdint.h
new file mode 100644
index 0000000..988e639
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdint.h
@@ -0,0 +1,34 @@
+/*
+ * bits64/stdint.h
+ */
+
+#ifndef _BITSIZE_STDINT_H
+#define _BITSIZE_STDINT_H
+
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long int int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long int uint64_t;
+
+typedef long int int_fast16_t;
+typedef long int int_fast32_t;
+
+typedef unsigned long int uint_fast16_t;
+typedef unsigned long int uint_fast32_t;
+
+typedef long int intptr_t;
+typedef unsigned long int uintptr_t;
+
+#define __INT64_C(c) c ## L
+#define __UINT64_C(c) c ## UL
+
+#define __PRI64_RANK "l"
+#define __PRIFAST_RANK "l"
+#define __PRIPTR_RANK "l"
+
+#endif /* _BITSIZE_STDINT_H */
diff --git a/usr/include/bits64/bitsize/stdintconst.h b/usr/include/bits64/bitsize/stdintconst.h
new file mode 100644
index 0000000..24e8eb6
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdintconst.h
@@ -0,0 +1,18 @@
+/*
+ * bits64/stdintconst.h
+ */
+
+#ifndef _BITSIZE_STDINTCONST_H
+#define _BITSIZE_STDINTCONST_H
+
+#define INT_FAST16_C(c) INT64_C(c)
+#define INT_FAST32_C(c) INT64_C(c)
+
+#define UINT_FAST16_C(c) UINT64_C(c)
+#define UINT_FAST32_C(c) UINT64_C(c)
+
+#define INTPTR_C(c) INT64_C(c)
+#define UINTPTR_C(c) UINT64_C(c)
+#define PTRDIFF_C(c) INT64_C(c)
+
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/usr/include/bits64/bitsize/stdintlimits.h b/usr/include/bits64/bitsize/stdintlimits.h
new file mode 100644
index 0000000..4ef07f7
--- /dev/null
+++ b/usr/include/bits64/bitsize/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits64/stdintlimits.h
+ */
+
+#ifndef _BITSIZE_STDINTLIMITS_H
+#define _BITSIZE_STDINTLIMITS_H
+
+#define INT_FAST16_MIN INT64_MIN
+#define INT_FAST32_MIN INT64_MIN
+#define INT_FAST16_MAX INT64_MAX
+#define INT_FAST32_MAX INT64_MAX
+#define UINT_FAST16_MAX UINT64_MAX
+#define UINT_FAST32_MAX UINT64_MAX
+
+#define INTPTR_MIN INT64_MIN
+#define INTPTR_MAX INT64_MAX
+#define UINTPTR_MAX UINT64_MAX
+
+#define PTRDIFF_MIN INT64_MIN
+#define PTRDIFF_MAX INT64_MAX
+#define SIZE_MAX UINT64_MAX
+
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/byteswap.h b/usr/include/byteswap.h
new file mode 100644
index 0000000..d70f1f9
--- /dev/null
+++ b/usr/include/byteswap.h
@@ -0,0 +1,15 @@
+/*
+ * byteswap.h
+ */
+
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+#include <sys/types.h>
+#include <asm/byteorder.h>
+
+#define bswap_16(x) __swab16(x)
+#define bswap_32(x) __swab32(x)
+#define bswap_64(x) __swab64(x)
+
+#endif /* _BYTESWAP_H */
diff --git a/usr/include/ctype.h b/usr/include/ctype.h
new file mode 100644
index 0000000..14a2f2d
--- /dev/null
+++ b/usr/include/ctype.h
@@ -0,0 +1,174 @@
+/*
+ * ctype.h
+ *
+ * This assumes ISO 8859-1, being a reasonable superset of ASCII.
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+
+/*
+ * This relies on the following definitions:
+ *
+ * cntrl = !print
+ * alpha = upper|lower
+ * graph = punct|alpha|digit
+ * blank = '\t' || ' ' (per POSIX requirement)
+ */
+enum {
+ __ctype_upper = (1 << 0),
+ __ctype_lower = (1 << 1),
+ __ctype_digit = (1 << 2),
+ __ctype_xdigit = (1 << 3),
+ __ctype_space = (1 << 4),
+ __ctype_print = (1 << 5),
+ __ctype_punct = (1 << 6),
+ __ctype_cntrl = (1 << 7),
+};
+
+__extern int isalnum(int);
+__extern int isalpha(int);
+__extern int isascii(int);
+__extern int isblank(int);
+__extern int iscntrl(int);
+__extern int isdigit(int);
+__extern int isgraph(int);
+__extern int islower(int);
+__extern int isprint(int);
+__extern int ispunct(int);
+__extern int isspace(int);
+__extern int isupper(int);
+__extern int isxdigit(int);
+__extern int toupper(int);
+__extern int tolower(int);
+
+extern const unsigned char __ctypes[];
+
+__must_inline int __ctype_isalnum(int);
+__must_inline int __ctype_isalpha(int);
+__must_inline int __ctype_isascii(int);
+__must_inline int __ctype_isblank(int);
+__must_inline int __ctype_iscntrl(int);
+__must_inline int __ctype_isdigit(int);
+__must_inline int __ctype_isgraph(int);
+__must_inline int __ctype_islower(int);
+__must_inline int __ctype_isprint(int);
+__must_inline int __ctype_ispunct(int);
+__must_inline int __ctype_isspace(int);
+__must_inline int __ctype_isupper(int);
+__must_inline int __ctype_isxdigit(int);
+
+__must_inline int __ctype_isalnum(int __c)
+{
+ return __ctypes[__c + 1] &
+ (__ctype_upper | __ctype_lower | __ctype_digit);
+}
+
+__must_inline int __ctype_isalpha(int __c)
+{
+ return __ctypes[__c + 1] & (__ctype_upper | __ctype_lower);
+}
+
+__must_inline int __ctype_isascii(int __c)
+{
+ return !(__c & ~0x7f);
+}
+
+__must_inline int __ctype_isblank(int __c)
+{
+ return (__c == '\t') || (__c == ' ');
+}
+
+__must_inline int __ctype_iscntrl(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_cntrl;
+}
+
+__must_inline int __ctype_isdigit(int __c)
+{
+ return ((unsigned)__c - '0') <= 9;
+}
+
+__must_inline int __ctype_isgraph(int __c)
+{
+ return __ctypes[__c + 1] &
+ (__ctype_upper | __ctype_lower | __ctype_digit | __ctype_punct);
+}
+
+__must_inline int __ctype_islower(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_lower;
+}
+
+__must_inline int __ctype_isprint(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_print;
+}
+
+__must_inline int __ctype_ispunct(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_punct;
+}
+
+__must_inline int __ctype_isspace(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_space;
+}
+
+__must_inline int __ctype_isupper(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_upper;
+}
+
+__must_inline int __ctype_isxdigit(int __c)
+{
+ return __ctypes[__c + 1] & __ctype_xdigit;
+}
+
+/* Note: this is decimal, not hex, to avoid accidental promotion to unsigned */
+#define _toupper(__c) ((__c) & ~32)
+#define _tolower(__c) ((__c) | 32)
+
+__must_inline int __ctype_toupper(int);
+__must_inline int __ctype_tolower(int);
+
+__must_inline int __ctype_toupper(int __c)
+{
+ return __ctype_islower(__c) ? _toupper(__c) : __c;
+}
+
+__must_inline int __ctype_tolower(int __c)
+{
+ return __ctype_isupper(__c) ? _tolower(__c) : __c;
+}
+
+#ifdef __CTYPE_NO_INLINE
+# define __CTYPEFUNC(X) \
+ __extern int X(int);
+#else
+#define __CTYPEFUNC(X) \
+ __extern_inline int X(int __c) \
+ { \
+ return __ctype_##X(__c); \
+ }
+#endif
+
+__CTYPEFUNC(isalnum)
+__CTYPEFUNC(isalpha)
+__CTYPEFUNC(isascii)
+__CTYPEFUNC(isblank)
+__CTYPEFUNC(iscntrl)
+__CTYPEFUNC(isdigit)
+__CTYPEFUNC(isgraph)
+__CTYPEFUNC(islower)
+__CTYPEFUNC(isprint)
+__CTYPEFUNC(ispunct)
+__CTYPEFUNC(isspace)
+__CTYPEFUNC(isupper)
+__CTYPEFUNC(isxdigit)
+__CTYPEFUNC(toupper)
+__CTYPEFUNC(tolower)
+#endif /* _CTYPE_H */
diff --git a/usr/include/dirent.h b/usr/include/dirent.h
new file mode 100644
index 0000000..43df503
--- /dev/null
+++ b/usr/include/dirent.h
@@ -0,0 +1,43 @@
+/*
+ * dirent.h
+ */
+
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#include <klibc/compiler.h>
+#include <klibc/extern.h>
+#include <klibc/sysconfig.h>
+#include <sys/dirent.h>
+
+struct _IO_dir {
+ int __fd;
+
+#ifdef __KLIBC_DIRENT_INTERNALS
+ /* These fields for internal use only */
+
+ size_t bytes_left;
+ struct dirent *next;
+ /* Declaring this as an array of struct enforces correct alignment */
+ struct dirent buffer[_KLIBC_BUFSIZ / sizeof(struct dirent)];
+#endif
+};
+typedef struct _IO_dir DIR;
+
+__extern DIR *fdopendir(int);
+__extern DIR *opendir(const char *);
+__extern struct dirent *readdir(DIR *);
+__extern int closedir(DIR *);
+__static_inline int dirfd(DIR * __d)
+{
+ return __d->__fd;
+}
+
+__extern int scandir(const char *, struct dirent ***,
+ int (*)(const struct dirent *),
+ int (*)(const struct dirent **,
+ const struct dirent **));
+
+__extern int alphasort(const struct dirent **, const struct dirent **);
+
+#endif /* _DIRENT_H */
diff --git a/usr/include/elf.h b/usr/include/elf.h
new file mode 100644
index 0000000..c543a81
--- /dev/null
+++ b/usr/include/elf.h
@@ -0,0 +1,11 @@
+/*
+ * elf.h
+ */
+
+#ifndef _ELF_H
+#define _ELF_H
+
+#include <sys/elf32.h>
+#include <sys/elf64.h>
+
+#endif /* _ELF_H */
diff --git a/usr/include/endian.h b/usr/include/endian.h
new file mode 100644
index 0000000..61cda3a
--- /dev/null
+++ b/usr/include/endian.h
@@ -0,0 +1,21 @@
+/*
+ * endian.h
+ */
+
+#ifndef _ENDIAN_H
+#define _ENDIAN_H
+
+#include <klibc/endian.h>
+
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#define BIG_ENDIAN __BIG_ENDIAN
+#define PDP_ENDIAN __PDP_ENDIAN
+#define BYTE_ORDER __BYTE_ORDER
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define __LONG_LONG_PAIR(HI, LO) LO, HI
+#elif __BYTE_ORDER == __BIG_ENDIAN
+# define __LONG_LONG_PAIR(HI, LO) HI, LO
+#endif
+
+#endif /* _ENDIAN_H */
diff --git a/usr/include/errno.h b/usr/include/errno.h
new file mode 100644
index 0000000..d8e20bd
--- /dev/null
+++ b/usr/include/errno.h
@@ -0,0 +1,13 @@
+/*
+ * errno.h
+ */
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+#include <klibc/extern.h>
+#include <asm/errno.h>
+
+__extern int errno;
+
+#endif /* _ERRNO_H */
diff --git a/usr/include/fcntl.h b/usr/include/fcntl.h
new file mode 100644
index 0000000..cb2e4e5
--- /dev/null
+++ b/usr/include/fcntl.h
@@ -0,0 +1,67 @@
+/*
+ * fcntl.h
+ */
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <klibc/seek.h>
+#include <sys/types.h>
+#if defined(__mips__) && ! defined(__mips64)
+# include <klibc/archfcntl.h>
+#elif _BITSIZE == 32
+/* We want a struct flock with 64-bit offsets, which we define below */
+# define HAVE_ARCH_STRUCT_FLOCK
+#endif
+#include <linux/fcntl.h>
+#include <bitsize.h>
+
+#if !defined(__mips__) && _BITSIZE == 32
+
+/*
+ * <linux/fcntl.h> defines struct flock with offsets of type
+ * __kernel_off_t (= long) and struct flock64 with offsets of
+ * type __kernel_loff_t (= long long). We want struct flock
+ * to have 64-bit offsets, so we define it here.
+ */
+
+struct flock {
+ short l_type;
+ short l_whence;
+ __kernel_loff_t l_start;
+ __kernel_loff_t l_len;
+ __kernel_pid_t l_pid;
+#ifdef __ARCH_FLOCK64_PAD
+ __ARCH_FLOCK64_PAD
+#endif
+};
+
+#ifdef F_GETLK64
+# undef F_GETLK
+# define F_GETLK F_GETLK64
+#endif
+
+#ifdef F_SETLK64
+# undef F_SETLK
+# define F_SETLK F_SETLK64
+#endif
+
+#ifdef F_SETLKW64
+# undef F_SETLKW
+# define F_SETLKW F_SETLKW64
+#endif
+
+#endif /* _BITSIZE == 32 */
+
+/* This is defined here as well as in <unistd.h> */
+#ifndef _KLIBC_IN_OPEN_C
+__extern int open(const char *, int, ...);
+__extern int openat(int, const char *, int, ...);
+#endif
+
+__extern int creat(const char *, mode_t);
+__extern int fcntl(int, int, ...);
+
+#endif /* _FCNTL_H */
diff --git a/usr/include/fnmatch.h b/usr/include/fnmatch.h
new file mode 100644
index 0000000..0d88140
--- /dev/null
+++ b/usr/include/fnmatch.h
@@ -0,0 +1,15 @@
+#ifndef _FNMATCH_H
+#define _FNMATCH_H
+
+#include <klibc/extern.h>
+
+#define FNM_NOMATCH 1
+
+#define FNM_PATHNAME 1
+#define FNM_FILE_NAME FNM_PATHNAME
+#define FNM_NOESCAPE 2
+#define FNM_PERIOD 4
+
+__extern int fnmatch(const char *, const char *, int);
+
+#endif /* _FNMATCH_H */
diff --git a/usr/include/getopt.h b/usr/include/getopt.h
new file mode 100644
index 0000000..71c41cd
--- /dev/null
+++ b/usr/include/getopt.h
@@ -0,0 +1,22 @@
+#ifndef _GETOPT_H
+#define _GETOPT_H
+
+#include <klibc/extern.h>
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+enum {
+ no_argument = 0,
+ required_argument = 1,
+ optional_argument = 2,
+};
+
+__extern int getopt_long(int, char *const *, const char *,
+ const struct option *, int *);
+
+#endif /* _GETOPT_H */
diff --git a/usr/include/grp.h b/usr/include/grp.h
new file mode 100644
index 0000000..77ce399
--- /dev/null
+++ b/usr/include/grp.h
@@ -0,0 +1,22 @@
+/*
+ * grp.h
+ */
+
+#ifndef _GRP_H
+#define _GRP_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+struct group {
+ char *gr_name;
+ char *gr_passwd;
+ gid_t gr_gid;
+ char **gr_mem;
+};
+
+__extern int setgroups(size_t, const gid_t *);
+__extern struct group *getgrgid(gid_t);
+__extern struct group *getgrnam(const char *);
+
+#endif /* _GRP_H */
diff --git a/usr/include/inttypes.h b/usr/include/inttypes.h
new file mode 100644
index 0000000..29311fe
--- /dev/null
+++ b/usr/include/inttypes.h
@@ -0,0 +1,226 @@
+/*
+ * inttypes.h
+ */
+
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <stddef.h>
+
+static __inline__ intmax_t imaxabs(intmax_t __n)
+{
+ return (__n < (intmax_t) 0) ? -__n : __n;
+}
+
+__extern intmax_t strtoimax(const char *, char **, int);
+__extern uintmax_t strtoumax(const char *, char **, int);
+
+/* extensions */
+__extern intmax_t strntoimax(const char *, char **, int, size_t);
+__extern uintmax_t strntoumax(const char *, char **, int, size_t);
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 __PRI64_RANK "d"
+
+#define PRIdLEAST8 "d"
+#define PRIdLEAST16 "d"
+#define PRIdLEAST32 "d"
+#define PRIdLEAST64 __PRI64_RANK "d"
+
+#define PRIdFAST8 "d"
+#define PRIdFAST16 __PRIFAST_RANK "d"
+#define PRIdFAST32 __PRIFAST_RANK "d"
+#define PRIdFAST64 __PRI64_RANK "d"
+
+#define PRIdMAX __PRI64_RANK "d"
+#define PRIdPTR __PRIPTR_RANK "d"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 __PRI64_RANK "i"
+
+#define PRIiLEAST8 "i"
+#define PRIiLEAST16 "i"
+#define PRIiLEAST32 "i"
+#define PRIiLEAST64 __PRI64_RANK "i"
+
+#define PRIiFAST8 "i"
+#define PRIiFAST16 __PRIFAST_RANK "i"
+#define PRIiFAST32 __PRIFAST_RANK "i"
+#define PRIiFAST64 __PRI64_RANK "i"
+
+#define PRIiMAX __PRI64_RANK "i"
+#define PRIiPTR __PRIPTR_RANK "i"
+
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 __PRI64_RANK "o"
+
+#define PRIoLEAST8 "o"
+#define PRIoLEAST16 "o"
+#define PRIoLEAST32 "o"
+#define PRIoLEAST64 __PRI64_RANK "o"
+
+#define PRIoFAST8 "o"
+#define PRIoFAST16 __PRIFAST_RANK "o"
+#define PRIoFAST32 __PRIFAST_RANK "o"
+#define PRIoFAST64 __PRI64_RANK "o"
+
+#define PRIoMAX __PRI64_RANK "o"
+#define PRIoPTR __PRIPTR_RANK "o"
+
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 __PRI64_RANK "u"
+
+#define PRIuLEAST8 "u"
+#define PRIuLEAST16 "u"
+#define PRIuLEAST32 "u"
+#define PRIuLEAST64 __PRI64_RANK "u"
+
+#define PRIuFAST8 "u"
+#define PRIuFAST16 __PRIFAST_RANK "u"
+#define PRIuFAST32 __PRIFAST_RANK "u"
+#define PRIuFAST64 __PRI64_RANK "u"
+
+#define PRIuMAX __PRI64_RANK "u"
+#define PRIuPTR __PRIPTR_RANK "u"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 __PRI64_RANK "x"
+
+#define PRIxLEAST8 "x"
+#define PRIxLEAST16 "x"
+#define PRIxLEAST32 "x"
+#define PRIxLEAST64 __PRI64_RANK "x"
+
+#define PRIxFAST8 "x"
+#define PRIxFAST16 __PRIFAST_RANK "x"
+#define PRIxFAST32 __PRIFAST_RANK "x"
+#define PRIxFAST64 __PRI64_RANK "x"
+
+#define PRIxMAX __PRI64_RANK "x"
+#define PRIxPTR __PRIPTR_RANK "x"
+
+#define PRIX8 "X"
+#define PRIX16 "X"
+#define PRIX32 "X"
+#define PRIX64 __PRI64_RANK "X"
+
+#define PRIXLEAST8 "X"
+#define PRIXLEAST16 "X"
+#define PRIXLEAST32 "X"
+#define PRIXLEAST64 __PRI64_RANK "X"
+
+#define PRIXFAST8 "X"
+#define PRIXFAST16 __PRIFAST_RANK "X"
+#define PRIXFAST32 __PRIFAST_RANK "X"
+#define PRIXFAST64 __PRI64_RANK "X"
+
+#define PRIXMAX __PRI64_RANK "X"
+#define PRIXPTR __PRIPTR_RANK "X"
+
+#define SCNd8 "hhd"
+#define SCNd16 "hd"
+#define SCNd32 "d"
+#define SCNd64 __PRI64_RANK "d"
+
+#define SCNdLEAST8 "hhd"
+#define SCNdLEAST16 "hd"
+#define SCNdLEAST32 "d"
+#define SCNdLEAST64 __PRI64_RANK "d"
+
+#define SCNdFAST8 "hhd"
+#define SCNdFAST16 __PRIFAST_RANK "d"
+#define SCNdFAST32 __PRIFAST_RANK "d"
+#define SCNdFAST64 __PRI64_RANK "d"
+
+#define SCNdMAX __PRI64_RANK "d"
+#define SCNdPTR __PRIPTR_RANK "d"
+
+#define SCNi8 "hhi"
+#define SCNi16 "hi"
+#define SCNi32 "i"
+#define SCNi64 __PRI64_RANK "i"
+
+#define SCNiLEAST8 "hhi"
+#define SCNiLEAST16 "hi"
+#define SCNiLEAST32 "i"
+#define SCNiLEAST64 __PRI64_RANK "i"
+
+#define SCNiFAST8 "hhi"
+#define SCNiFAST16 __PRIFAST_RANK "i"
+#define SCNiFAST32 __PRIFAST_RANK "i"
+#define SCNiFAST64 __PRI64_RANK "i"
+
+#define SCNiMAX __PRI64_RANK "i"
+#define SCNiPTR __PRIPTR_RANK "i"
+
+#define SCNo8 "hho"
+#define SCNo16 "ho"
+#define SCNo32 "o"
+#define SCNo64 __PRI64_RANK "o"
+
+#define SCNoLEAST8 "hho"
+#define SCNoLEAST16 "ho"
+#define SCNoLEAST32 "o"
+#define SCNoLEAST64 __PRI64_RANK "o"
+
+#define SCNoFAST8 "hho"
+#define SCNoFAST16 __PRIFAST_RANK "o"
+#define SCNoFAST32 __PRIFAST_RANK "o"
+#define SCNoFAST64 __PRI64_RANK "o"
+
+#define SCNoMAX __PRI64_RANK "o"
+#define SCNoPTR __PRIPTR_RANK "o"
+
+#define SCNu8 "hhu"
+#define SCNu16 "hu"
+#define SCNu32 "u"
+#define SCNu64 __PRI64_RANK "u"
+
+#define SCNuLEAST8 "hhu"
+#define SCNuLEAST16 "hu"
+#define SCNuLEAST32 "u"
+#define SCNuLEAST64 __PRI64_RANK "u"
+
+#define SCNuFAST8 "hhu"
+#define SCNuFAST16 __PRIFAST_RANK "u"
+#define SCNuFAST32 __PRIFAST_RANK "u"
+#define SCNuFAST64 __PRI64_RANK "u"
+
+#define SCNuMAX __PRI64_RANK "u"
+#define SCNuPTR __PRIPTR_RANK "u"
+
+#define SCNx8 "hhx"
+#define SCNx16 "hx"
+#define SCNx32 "x"
+#define SCNx64 __PRI64_RANK "x"
+
+#define SCNxLEAST8 "hhx"
+#define SCNxLEAST16 "hx"
+#define SCNxLEAST32 "x"
+#define SCNxLEAST64 __PRI64_RANK "x"
+
+#define SCNxFAST8 "hhx"
+#define SCNxFAST16 __PRIFAST_RANK "x"
+#define SCNxFAST32 __PRIFAST_RANK "x"
+#define SCNxFAST64 __PRI64_RANK "x"
+
+#define SCNxMAX __PRI64_RANK "x"
+#define SCNxPTR __PRIPTR_RANK "x"
+
+#endif
+
+#endif /* _INTTYPES_H */
diff --git a/usr/include/klibc/compiler.h b/usr/include/klibc/compiler.h
new file mode 100644
index 0000000..ff5a006
--- /dev/null
+++ b/usr/include/klibc/compiler.h
@@ -0,0 +1,158 @@
+/*
+ * klibc/compiler.h
+ *
+ * Various compiler features
+ */
+
+#ifndef _KLIBC_COMPILER_H
+#define _KLIBC_COMPILER_H
+
+/* Specific calling conventions */
+/* __cdecl is used when we want varadic and non-varadic functions to have
+ the same binary calling convention. */
+#ifdef __i386__
+# ifdef __GNUC__
+# define __cdecl __attribute__((cdecl,regparm(0)))
+# else
+ /* Most other C compilers have __cdecl as a keyword */
+# endif
+#else
+# define __cdecl /* Meaningless on non-i386 */
+#endif
+
+/*
+ * How to declare a function which should be inlined or instantiated locally
+ */
+#ifdef __GNUC__
+# ifdef __GNUC_STDC_INLINE__
+# define __static_inline static __inline__ __attribute__((__gnu_inline__))
+# else
+# define __static_inline static __inline__
+# endif
+#else
+# define __static_inline inline /* Just hope this works... */
+#endif
+
+/*
+ * How to declare a function which should be inlined or have a call to
+ * an external module
+ */
+#ifdef __GNUC__
+# ifdef __GNUC_STDC_INLINE__
+# define __extern_inline extern __inline__ __attribute__((__gnu_inline__))
+# else
+# define __extern_inline extern __inline__
+# endif
+#else
+# define __extern_inline inline /* Just hope this works... */
+#endif
+
+/* How to declare a function that *must* be inlined */
+/* Use "extern inline" even in the gcc3+ case to avoid warnings in ctype.h */
+#ifdef __GNUC__
+# if __GNUC__ >= 3
+# define __must_inline __extern_inline __attribute__((__always_inline__))
+# else
+# define __must_inline extern __inline__
+# endif
+#else
+# define __must_inline inline /* Just hope this works... */
+#endif
+
+/* How to declare a function that does not return */
+#ifdef __GNUC__
+# define __noreturn void __attribute__((noreturn))
+#else
+# define __noreturn void
+#endif
+
+/* "const" function:
+
+ Many functions do not examine any values except their arguments,
+ and have no effects except the return value. Basically this is
+ just slightly more strict class than the `pure' attribute above,
+ since function is not allowed to read global memory.
+
+ Note that a function that has pointer arguments and examines the
+ data pointed to must _not_ be declared `const'. Likewise, a
+ function that calls a non-`const' function usually must not be
+ `const'. It does not make sense for a `const' function to return
+ `void'.
+*/
+#ifdef __GNUC__
+# define __constfunc __attribute__((const))
+#else
+# define __constfunc
+#endif
+#undef __attribute_const__
+#define __attribute_const__ __constfunc
+
+/* "pure" function:
+
+ Many functions have no effects except the return value and their
+ return value depends only on the parameters and/or global
+ variables. Such a function can be subject to common subexpression
+ elimination and loop optimization just as an arithmetic operator
+ would be. These functions should be declared with the attribute
+ `pure'.
+*/
+#ifdef __GNUC__
+# define __purefunc __attribute__((pure))
+#else
+# define __purefunc
+#endif
+#undef __attribute_pure__
+#define __attribute_pure__ __purefunc
+
+/* Format attribute */
+#ifdef __GNUC__
+# define __formatfunc(t,f,a) __attribute__((format(t,f,a)))
+#else
+# define __formatfunc(t,f,a)
+#endif
+
+/* malloc() function (returns unaliased pointer) */
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+# define __mallocfunc __attribute__((malloc))
+#else
+# define __mallocfunc
+#endif
+
+/* likely/unlikely */
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+# define __likely(x) __builtin_expect(!!(x), 1)
+# define __unlikely(x) __builtin_expect(!!(x), 0)
+#else
+# define __likely(x) (!!(x))
+# define __unlikely(x) (!!(x))
+#endif
+
+/* Possibly unused function */
+#ifdef __GNUC__
+# define __unusedfunc __attribute__((unused))
+#else
+# define __unusedfunc
+#endif
+
+/* It's all user space... */
+#define __user
+
+/* The bitwise attribute: disallow arithmetric operations */
+#ifdef __CHECKER__ /* sparse only */
+# define __bitwise __attribute__((bitwise))
+#else
+# define __bitwise
+#endif
+
+/* Shut up unused warnings */
+#ifdef __GNUC__
+# define __attribute_used__ __attribute__((used))
+#else
+# define __attribute_used__
+#endif
+
+/* Compiler pragma to make an alias symbol */
+#define __ALIAS(__t, __f, __p, __a) \
+ __t __f __p __attribute__((weak, alias(#__a)));
+
+#endif
diff --git a/usr/include/klibc/diverr.h b/usr/include/klibc/diverr.h
new file mode 100644
index 0000000..e70887e
--- /dev/null
+++ b/usr/include/klibc/diverr.h
@@ -0,0 +1,15 @@
+/*
+ * klibc/diverr.h
+ */
+
+#ifndef _KLIBC_DIVERR_H
+#define _KLIBC_DIVERR_H
+
+#include <signal.h>
+
+static __inline__ void __divide_error(void)
+{
+ raise(SIGFPE);
+}
+
+#endif /* _KLIBC_DIVERR_H */
diff --git a/usr/include/klibc/endian.h b/usr/include/klibc/endian.h
new file mode 100644
index 0000000..8586888
--- /dev/null
+++ b/usr/include/klibc/endian.h
@@ -0,0 +1,39 @@
+/*
+ * klibc/endian.h
+ *
+ * Like <endian.h>, but export only double-underscore symbols
+ */
+
+#ifndef _KLIBC_ENDIAN_H
+#define _KLIBC_ENDIAN_H
+
+#include <sys/types.h>
+#include <asm/byteorder.h>
+
+/* Linux' asm/byteorder.h defines either __LITTLE_ENDIAN or
+ __BIG_ENDIAN, but the glibc/BSD-ish macros expect both to be
+ defined with __BYTE_ORDER defining which is actually used... */
+
+#if defined(__LITTLE_ENDIAN)
+# undef __LITTLE_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN 4321
+# define __PDP_ENDIAN 3412
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#elif defined(__BIG_ENDIAN)
+# undef __BIG_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN 4321
+# define __PDP_ENDIAN 3412
+# define __BYTE_ORDER __BIG_ENDIAN
+#elif defined(__PDP_ENDIAN)
+# undef __PDP_ENDIAN
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN 4321
+# define __PDP_ENDIAN 3412
+# define __BYTE_ORDER __PDP_ENDIAN
+#else
+# error "Unknown byte order!"
+#endif
+
+#endif /* _KLIBC_ENDIAN_H */
diff --git a/usr/include/klibc/extern.h b/usr/include/klibc/extern.h
new file mode 100644
index 0000000..7d7c7b8
--- /dev/null
+++ b/usr/include/klibc/extern.h
@@ -0,0 +1,16 @@
+/*
+ * klibc/extern.h
+ */
+
+#ifndef _KLIBC_EXTERN_H
+#define _KLIBC_EXTERN_H
+
+#ifdef __cplusplus
+#define __extern extern "C"
+#else
+#define __extern extern
+#endif
+
+#define __alias(x) __attribute__((weak, alias(x)))
+
+#endif /* _KLIBC_EXTERN_H */
diff --git a/usr/include/klibc/seek.h b/usr/include/klibc/seek.h
new file mode 100644
index 0000000..e8ffe25
--- /dev/null
+++ b/usr/include/klibc/seek.h
@@ -0,0 +1,14 @@
+/*
+ * klibc/seek.h
+ *
+ * SEEK constants - needed by stdio.h, fcntl.h, and unistd.h
+ */
+
+#ifndef _KLIBC_SEEK_H
+#define _KLIBC_SEEK_H
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#endif /* _KLIBC_SEEK_H */
diff --git a/usr/include/klibc/sysconfig.h b/usr/include/klibc/sysconfig.h
new file mode 100644
index 0000000..5d16f61
--- /dev/null
+++ b/usr/include/klibc/sysconfig.h
@@ -0,0 +1,235 @@
+/*
+ * klibc/sysconfig.h
+ *
+ * Allows for definitions of some things which may be system-dependent
+ * NOTE: this file must not result in any output from the preprocessor.
+ */
+
+#ifndef _KLIBC_SYSCONFIG_H
+#define _KLIBC_SYSCONFIG_H
+
+#include <klibc/archconfig.h>
+#include <asm/unistd.h>
+
+/*
+ * These are the variables that can be defined in <klibc/archconfig.h>.
+ * For boolean options, #define to 0 to disable, #define to 1 to enable.
+ *
+ * If undefined, they will be given defaults here.
+ */
+
+
+/*
+ * _KLIBC_NO_MMU:
+ *
+ * Indicates this architecture doesn't have an MMU, and therefore
+ * does not have the sys_fork and sys_brk system calls.
+ */
+/* Default to having an MMU if we can find the fork system call */
+#ifndef _KLIBC_NO_MMU
+# if defined(__NR_fork)
+# define _KLIBC_NO_MMU 0
+# else
+# define _KLIBC_NO_MMU 1
+# endif
+#endif
+
+
+/*
+ * _KLIBC_REAL_VFORK:
+ *
+ * Indicates that this architecture has a real vfork() system call.
+ * This is the default if sys_vfork exists; if there is an
+ * architecture-dependent implementation of vfork(), define this
+ * symbol.
+ */
+#ifndef _KLIBC_REAL_VFORK
+# if defined(__NR_vfork)
+# define _KLIBC_REAL_VFORK 1
+# else
+# define _KLIBC_REAL_VFORK 0
+# endif
+#endif
+
+
+/*
+ * _KLIBC_USE_MMAP2:
+ *
+ * Indicates that this architecture should use sys_mmap2 instead
+ * of sys_mmap. This is the default on 32-bit architectures, assuming
+ * sys_mmap2 exists.
+ */
+#ifndef _KLIBC_USE_MMAP2
+# if (_BITSIZE == 32 && defined(__NR_mmap2)) || \
+ (_BITSIZE == 64 && !defined(__NR_mmap))
+# define _KLIBC_USE_MMAP2 1
+# else
+# define _KLIBC_USE_MMAP2 0
+# endif
+#endif
+
+
+/*
+ * _KLIBC_MMAP2_SHIFT:
+ *
+ * Indicate the shift of the offset parameter in sys_mmap2.
+ * On most architectures, this is always 12, but on some
+ * architectures it can be a different number, or the current
+ * page size. If this is dependent on the page size, define
+ * this to an expression which includes __getpageshift().
+ */
+#ifndef _KLIBC_MMAP2_SHIFT
+# define _KLIBC_MMAP2_SHIFT 12
+#endif
+
+
+/*
+ * _KLIBC_MALLOC_USES_SBRK:
+ *
+ * Indicates that malloc() should use sbrk() to obtain raw memory
+ * from the system, rather than mmap().
+ */
+/* Default to get memory using mmap() */
+#ifndef _KLIBC_MALLOC_USES_SBRK
+# define _KLIBC_MALLOC_USES_SBRK 0
+#endif
+
+
+/*
+ * _KLIBC_MALLOC_CHUNK_SIZE:
+ * This is the minimum chunk size we will ask the kernel for using
+ * malloc(); this should be a multiple of the page size and must
+ * be a power of 2.
+ */
+#ifndef _KLIBC_MALLOC_CHUNK_SIZE
+# define _KLIBC_MALLOC_CHUNK_SIZE 65536
+#endif
+
+
+/*
+ * _KLIBC_BUFSIZ:
+ * This is the size of an stdio buffer. By default this is
+ * _KLIBC_MALLOC_CHUNK_SIZE/4, which allows the three standard
+ * streams to fit inside a malloc chunk.
+ */
+#ifndef _KLIBC_BUFSIZ
+# define _KLIBC_BUFSIZ (_KLIBC_MALLOC_CHUNK_SIZE >> 2)
+#endif
+
+
+/*
+ * _KLIBC_SBRK_ALIGNMENT:
+ *
+ * This is the minimum alignment for the memory returned by
+ * sbrk(). It must be a power of 2. If _KLIBC_MALLOC_USES_SBRK
+ * is set it should be no smaller than the size of struct
+ * arena_header in malloc.h (== 4 pointers.)
+ */
+#ifndef _KLIBC_SBRK_ALIGNMENT
+# define _KLIBC_SBRK_ALIGNMENT 32
+#endif
+
+
+/*
+ * _KLIBC_NEEDS_SA_RESTORER:
+ *
+ * Some architectures, like x86-64 and some i386 Fedora kernels,
+ * do not provide a default sigreturn, and therefore must have
+ * SA_RESTORER set. On others, the default sigreturn requires an
+ * executable stack, which we should avoid.
+ */
+#ifndef _KLIBC_NEEDS_SA_RESTORER
+# define _KLIBC_NEEDS_SA_RESTORER 0
+#endif
+
+
+/*
+ * _KLIBC_NEEDS_SA_SIGINFO:
+ *
+ * On some architectures, the signal stack frame is set up for
+ * either sigreturn() or rt_sigreturn() depending on whether
+ * SA_SIGINFO is set. Where this is the case, and we provide our
+ * own restorer function, this must also be set so that the
+ * restorer can always use rt_sigreturn().
+ */
+#ifndef _KLIBC_NEEDS_SA_SIGINFO
+# define _KLIBC_NEEDS_SA_SIGINFO 0
+#endif
+
+
+/*
+ * _KLIBC_NEEDS_SIGACTION_FIXUP
+ *
+ * On some architectures, struct sigaction needs additional
+ * changes before passing to the kernel.
+ */
+#ifndef _KLIBC_NEEDS_SIGACTION_FIXUP
+# define _KLIBC_NEEDS_SIGACTION_FIXUP 0
+#endif
+
+
+/*
+ * _KLIBC_STATFS_F_TYPE_64:
+ *
+ * This indicates that the f_type, f_bsize, f_namelen,
+ * f_frsize, and f_spare fields of struct statfs are
+ * 64 bits long. This is normally the case for 64-bit
+ * platforms, and so is the default for those. See
+ * usr/include/sys/vfs.h for the exact details.
+ */
+#ifndef _KLIBC_STATFS_F_TYPE_64
+# define _KLIBC_STATFS_F_TYPE_64 (_BITSIZE == 64)
+#endif
+
+
+/*
+ * _KLIBC_STATFS_F_TYPE_32B:
+ *
+ * mips has it's own definition of statfs, which is
+ * different from any other 32 bit arch.
+ */
+#ifndef _KLIBC_STATFS_F_TYPE_32B
+# define _KLIBC_STATFS_F_TYPE_32B 0
+#endif
+
+
+/*
+ * _KLIBC_HAS_ARCHSOCKET_H
+ *
+ * This architecture has <klibc/archsocket.h>
+ */
+#ifndef _KLIBC_HAS_ARCHSOCKET_H
+# define _KLIBC_HAS_ARCHSOCKET_H 0
+#endif
+
+
+/*
+ * _KLIBC_SYS_SOCKETCALL
+ *
+ * This architecture (e.g. SPARC) advertises socket-related
+ * system calls, which are not actually implemented. Use
+ * socketcalls unconditionally instead.
+ */
+#ifndef _KLIBC_SYS_SOCKETCALL
+# define _KLIBC_SYS_SOCKETCALL 0
+#endif
+
+/*
+ * _KLIBC_ARM_USE_BX
+ *
+ * This arm architecture supports bx instruction.
+ */
+#ifndef _KLIBC_ARM_USE_BX
+# define _KLIBC_ARM_USE_BX 0
+#endif
+
+/*
+ * _KLIBC_HAS_ARCHINIT
+ *
+ * This architecture has klibc/archinit.h and __libc_archinit()
+ */
+#ifndef _KLIBC_HAS_ARCHINIT
+# define _KLIBC_HAS_ARCHINIT 0
+#endif
+
+#endif /* _KLIBC_SYSCONFIG_H */
diff --git a/usr/include/limits.h b/usr/include/limits.h
new file mode 100644
index 0000000..464420a
--- /dev/null
+++ b/usr/include/limits.h
@@ -0,0 +1,47 @@
+/*
+ * limits.h
+ */
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+/* No multibyte characters seen */
+#define MB_LEN_MAX 1
+
+#define OPEN_MAX 256
+
+#define CHAR_BIT 8
+#define SHRT_BIT 16
+#define INT_BIT 32
+#define LONGLONG_BIT 64
+
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+#define UCHAR_MAX 255
+
+#ifdef __CHAR_UNSIGNED__
+# define CHAR_MIN 0
+# define CHAR_MAX UCHAR_MAX
+#else
+# define CHAR_MIN SCHAR_MIN
+# define CHAR_MAX SCHAR_MAX
+#endif
+
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+#define USHRT_MAX 65535
+
+#define INT_MIN (-2147483647-1)
+#define INT_MAX 2147483647
+#define UINT_MAX 4294967295U
+
+#define LLONG_MIN (-9223372036854775807LL-1)
+#define LLONG_MAX 9223372036854775807LL
+#define ULLONG_MAX 18446744073709551615ULL
+
+#include <bitsize/limits.h>
+#include <linux/limits.h>
+
+#define SSIZE_MAX LONG_MAX
+
+#endif /* _LIMITS_H */
diff --git a/usr/include/malloc.h b/usr/include/malloc.h
new file mode 100644
index 0000000..eb5fe34
--- /dev/null
+++ b/usr/include/malloc.h
@@ -0,0 +1,22 @@
+/*
+ * malloc.h
+ *
+ * Apparently people haven't caught on to use <stdlib.h>, which is the
+ * standard place for this crap since the 1980's...
+ */
+
+#ifndef _MALLOC_H
+#define _MALLOC_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+__extern void free(void *);
+
+__extern __mallocfunc void *malloc(size_t);
+__extern __mallocfunc void *zalloc(size_t);
+__extern __mallocfunc void *calloc(size_t, size_t);
+__extern __mallocfunc void *realloc(void *, size_t);
+
+#endif /* _MALLOC_H */
diff --git a/usr/include/mntent.h b/usr/include/mntent.h
new file mode 100644
index 0000000..104f35e
--- /dev/null
+++ b/usr/include/mntent.h
@@ -0,0 +1,21 @@
+#ifndef _MNTENT_H
+#define _MNTENT_H 1
+
+#define MNTTYPE_SWAP "swap"
+
+struct mntent {
+ char *mnt_fsname; /* name of mounted file system */
+ char *mnt_dir; /* file system path prefix */
+ char *mnt_type; /* mount type (see mntent.h) */
+ char *mnt_opts; /* mount options (see mntent.h) */
+ int mnt_freq; /* dump frequency in days */
+ int mnt_passno; /* pass number on parallel fsck */
+};
+
+extern FILE *setmntent(const char *, const char *);
+
+extern struct mntent *getmntent(FILE *);
+
+extern int endmntent(FILE *fp);
+
+#endif /* mntent.h */
diff --git a/usr/include/net/if.h b/usr/include/net/if.h
new file mode 100644
index 0000000..116a176
--- /dev/null
+++ b/usr/include/net/if.h
@@ -0,0 +1,8 @@
+#ifndef _NET_IF_H
+#define _NET_IF_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+
+#endif /* _NET_IF_H */
diff --git a/usr/include/net/if_arp.h b/usr/include/net/if_arp.h
new file mode 100644
index 0000000..6261eeb
--- /dev/null
+++ b/usr/include/net/if_arp.h
@@ -0,0 +1,3 @@
+/* if_arp.h needs sockaddr */
+#include <sys/socket.h>
+#include <linux/if_arp.h>
diff --git a/usr/include/net/if_packet.h b/usr/include/net/if_packet.h
new file mode 100644
index 0000000..33ee0aa
--- /dev/null
+++ b/usr/include/net/if_packet.h
@@ -0,0 +1,2 @@
+#include <sys/types.h>
+#include <linux/if_packet.h>
diff --git a/usr/include/net/route.h b/usr/include/net/route.h
new file mode 100644
index 0000000..8b4305b
--- /dev/null
+++ b/usr/include/net/route.h
@@ -0,0 +1,2 @@
+#include <sys/types.h>
+#include <linux/route.h>
diff --git a/usr/include/netinet/if_ether.h b/usr/include/netinet/if_ether.h
new file mode 100644
index 0000000..a0b8cde
--- /dev/null
+++ b/usr/include/netinet/if_ether.h
@@ -0,0 +1,2 @@
+#include <sys/types.h>
+#include <linux/if_ether.h>
diff --git a/usr/include/netinet/in.h b/usr/include/netinet/in.h
new file mode 100644
index 0000000..7a13d2d
--- /dev/null
+++ b/usr/include/netinet/in.h
@@ -0,0 +1,38 @@
+/*
+ * netinet/in.h
+ */
+
+#ifndef _NETINET_IN_H
+#define _NETINET_IN_H
+
+#include <sys/types.h>
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <endian.h> /* Must be included *before* <linux/in.h> */
+#include <sys/socket.h> /* Must be included *before* <linux/in.h> */
+#include <linux/in.h>
+
+#ifndef htons
+# define htons(x) __cpu_to_be16(x)
+#endif
+#ifndef ntohs
+# define ntohs(x) __be16_to_cpu(x)
+#endif
+#ifndef htonl
+# define htonl(x) __cpu_to_be32(x)
+#endif
+#ifndef ntohl
+# define ntohl(x) __be32_to_cpu(x)
+#endif
+#ifndef htonq
+# define htonq(x) __cpu_to_be64(x)
+#endif
+#ifndef ntohq
+# define ntohq(x) __be64_to_cpu(x)
+#endif
+
+#define IPPORT_RESERVED 1024
+
+__extern int bindresvport(int sd, struct sockaddr_in *sin);
+
+#endif /* _NETINET_IN_H */
diff --git a/usr/include/netinet/in6.h b/usr/include/netinet/in6.h
new file mode 100644
index 0000000..91a4e12
--- /dev/null
+++ b/usr/include/netinet/in6.h
@@ -0,0 +1,11 @@
+/*
+ * netinet/in6.h
+ */
+
+#ifndef _NETINET_IN6_H
+#define _NETINET_IN6_H
+
+#include <sys/types.h>
+#include <linux/in6.h>
+
+#endif /* _NETINET_IN6_H */
diff --git a/usr/include/netinet/ip.h b/usr/include/netinet/ip.h
new file mode 100644
index 0000000..4684bfd
--- /dev/null
+++ b/usr/include/netinet/ip.h
@@ -0,0 +1,13 @@
+/*
+ * netinet/ip.h
+ */
+
+#ifndef _NETINET_IP_H
+#define _NETINET_IP_H
+
+#include <endian.h>
+#include <linux/ip.h>
+
+#define IP_DF 0x4000 /* Flag: "Don't Fragment" */
+
+#endif /* _NETINET_IP_H */
diff --git a/usr/include/netinet/tcp.h b/usr/include/netinet/tcp.h
new file mode 100644
index 0000000..7fc4729
--- /dev/null
+++ b/usr/include/netinet/tcp.h
@@ -0,0 +1,11 @@
+/*
+ * netinet/tcp.h
+ */
+
+#ifndef _NETINET_TCP_H
+#define _NETINET_TCP_H
+
+#include <endian.h> /* Include *before* linux/tcp.h */
+#include <linux/tcp.h>
+
+#endif /* _NETINET_TCP_H */
diff --git a/usr/include/netinet/udp.h b/usr/include/netinet/udp.h
new file mode 100644
index 0000000..036f588
--- /dev/null
+++ b/usr/include/netinet/udp.h
@@ -0,0 +1,19 @@
+/*
+ * netinet/udp.h
+ */
+
+#ifndef _NETINET_UDP_H
+#define _NETINET_UDP_H
+
+/*
+ * We would include linux/udp.h, but it brings in too much other stuff
+ */
+
+struct udphdr {
+ __u16 source;
+ __u16 dest;
+ __u16 len;
+ __u16 check;
+};
+
+#endif /* _NETINET_UDP_H */
diff --git a/usr/include/netpacket/packet.h b/usr/include/netpacket/packet.h
new file mode 100644
index 0000000..33ee0aa
--- /dev/null
+++ b/usr/include/netpacket/packet.h
@@ -0,0 +1,2 @@
+#include <sys/types.h>
+#include <linux/if_packet.h>
diff --git a/usr/include/paths.h b/usr/include/paths.h
new file mode 100644
index 0000000..29ef301
--- /dev/null
+++ b/usr/include/paths.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)paths.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _PATHS_H_
+#define _PATHS_H_
+
+/* Default search path. */
+#define _PATH_DEFPATH "/usr/bin:/bin"
+/* All standard utilities path. */
+#define _PATH_STDPATH \
+ "/usr/bin:/bin:/usr/sbin:/sbin"
+
+#define _PATH_BSHELL "/bin/sh"
+#define _PATH_CONSOLE "/dev/console"
+#define _PATH_CSHELL "/bin/csh"
+#define _PATH_DEVDB "/var/run/dev.db"
+#define _PATH_DEVNULL "/dev/null"
+#define _PATH_DRUM "/dev/drum"
+#define _PATH_KLOG "/proc/kmsg"
+#define _PATH_KMEM "/dev/kmem"
+#define _PATH_LASTLOG "/var/log/lastlog"
+#define _PATH_MAILDIR "/var/mail"
+#define _PATH_MAN "/usr/share/man"
+#define _PATH_MEM "/dev/mem"
+#define _PATH_MNTTAB "/etc/fstab"
+#define _PATH_MOUNTED "/etc/mtab"
+#define _PATH_NOLOGIN "/etc/nologin"
+#define _PATH_PRESERVE "/var/lib"
+#define _PATH_RWHODIR "/var/spool/rwho"
+#define _PATH_SENDMAIL "/usr/sbin/sendmail"
+#define _PATH_SHADOW "/etc/shadow"
+#define _PATH_SHELLS "/etc/shells"
+#define _PATH_TTY "/dev/tty"
+#define _PATH_UNIX "/boot/vmlinux"
+#define _PATH_UTMP "/var/run/utmp"
+#define _PATH_VI "/bin/vi"
+#define _PATH_WTMP "/var/log/wtmp"
+
+/* Provide trailing slash, since mostly used for building pathnames. */
+#define _PATH_DEV "/dev/"
+#define _PATH_TMP "/tmp/"
+#define _PATH_VARDB "/var/db/"
+#define _PATH_VARRUN "/var/run/"
+#define _PATH_VARTMP "/var/tmp/"
+
+#endif /* !_PATHS_H_ */
diff --git a/usr/include/poll.h b/usr/include/poll.h
new file mode 100644
index 0000000..06fb41a
--- /dev/null
+++ b/usr/include/poll.h
@@ -0,0 +1 @@
+#include <sys/poll.h>
diff --git a/usr/include/pwd.h b/usr/include/pwd.h
new file mode 100644
index 0000000..a319e05
--- /dev/null
+++ b/usr/include/pwd.h
@@ -0,0 +1,21 @@
+#ifndef _PWD_H
+#define _PWD_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+struct passwd {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+__extern struct passwd *getpwuid(uid_t uid);
+
+__extern struct passwd *getpwnam(const char *name);
+
+#endif /* _PWD_H */
diff --git a/usr/include/sched.h b/usr/include/sched.h
new file mode 100644
index 0000000..6874855
--- /dev/null
+++ b/usr/include/sched.h
@@ -0,0 +1,39 @@
+/*
+ * sched.h
+ */
+
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+/* linux/sched.h is unusable; put the declarations we need here... */
+
+#define SCHED_OTHER 0
+#define SCHED_FIFO 1
+#define SCHED_RR 2
+
+struct sched_param {
+ int sched_priority;
+};
+
+__extern int sched_setscheduler(pid_t, int, const struct sched_param *);
+__extern int sched_setaffinity(pid_t, unsigned int, unsigned long *);
+__extern int sched_getaffinity(pid_t, unsigned int, unsigned long *);
+__extern int sched_yield(void);
+
+/* Raw interfaces to clone(2); only actually usable for non-VM-cloning */
+#ifdef __ia64__
+__extern pid_t __clone2(int, void *, void *);
+static __inline__ pid_t __clone(int _f, void *_sp)
+{
+ /* If this is used with _sp != 0 it will have the effect of the sp
+ and rsp growing away from a single point in opposite directions. */
+ return __clone2(_f, _sp, _sp);
+}
+#else
+__extern pid_t __clone(int, void *);
+#endif
+
+#endif /* _SCHED_H */
diff --git a/usr/include/setjmp.h b/usr/include/setjmp.h
new file mode 100644
index 0000000..5916cd8
--- /dev/null
+++ b/usr/include/setjmp.h
@@ -0,0 +1,48 @@
+/*
+ * setjmp.h
+ */
+
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <signal.h>
+
+#include <klibc/archsetjmp.h>
+
+__extern int setjmp(jmp_buf);
+__extern __noreturn longjmp(jmp_buf, int);
+
+/*
+ Whose bright idea was it to add unrelated functionality to just about
+ the only function in the standard C library (setjmp) which cannot be
+ wrapped by an ordinary function wrapper? Anyway, the damage is done,
+ and therefore, this wrapper *must* be inline. However, gcc will
+ complain if this is an inline function for unknown reason, and
+ therefore sigsetjmp() needs to be a macro.
+*/
+
+struct __sigjmp_buf {
+ jmp_buf __jmpbuf;
+ sigset_t __sigs;
+ unsigned char __sigs_saved;
+};
+
+typedef struct __sigjmp_buf sigjmp_buf[1];
+
+#define sigsetjmp(__env, __save) \
+({ \
+ struct __sigjmp_buf *__e = (__env); \
+ if (__save) { \
+ sigprocmask(0, NULL, &__e->__sigs); \
+ __e->__sigs_saved = 1; \
+ } else \
+ __e->__sigs_saved = 0; \
+ setjmp(__e->__jmpbuf); \
+})
+
+__extern __noreturn siglongjmp(sigjmp_buf, int);
+
+#endif /* _SETJMP_H */
diff --git a/usr/include/signal.h b/usr/include/signal.h
new file mode 100644
index 0000000..a513282
--- /dev/null
+++ b/usr/include/signal.h
@@ -0,0 +1,103 @@
+/*
+ * signal.h
+ */
+
+#ifndef _SIGNAL_H
+#define _SIGNAL_H
+
+#include <klibc/compiler.h>
+#include <klibc/extern.h>
+#include <string.h> /* For memset() */
+#include <limits.h> /* For LONG_BIT */
+#include <sys/types.h>
+
+#include <klibc/archsignal.h> /* Includes <asm/signal.h> if appropriate */
+
+/* glibc seems to use sig_atomic_t as "int" pretty much on all architectures.
+ Do the same, but allow the architecture to override. */
+#ifndef _KLIBC_HAS_ARCH_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+#endif
+
+/* Some architectures don't define these */
+#ifndef SA_RESETHAND
+# define SA_RESETHAND SA_ONESHOT
+#endif
+#ifndef SA_NODEFER
+# define SA_NODEFER SA_NOMASK
+#endif
+/* Some architectures define NSIG and not _NSIG or vice versa */
+#ifndef NSIG
+# define NSIG _NSIG
+#endif
+#ifndef _NSIG
+# define _NSIG NSIG
+#endif
+
+/* If we don't have any real-time signals available to userspace,
+ hide them all */
+#if SIGRTMAX <= SIGRTMIN
+# undef SIGRTMIN
+# undef SIGRTMAX
+#endif
+
+/* The kernel header files are inconsistent whether or not
+ SIGRTMAX is inclusive or exclusive. POSIX seems to state that
+ it's inclusive, however. */
+#if SIGRTMAX >= _NSIG
+# undef SIGRTMAX
+# define SIGRTMAX (_NSIG-1)
+#endif
+
+__extern const char *const sys_siglist[_NSIG];
+__extern const char *const sys_sigabbrev[_NSIG];
+
+/* This assumes sigset_t is either an unsigned long or an array of such,
+ and that _NSIG_BPW in the kernel is always LONG_BIT */
+
+static __inline__ int sigemptyset(sigset_t * __set)
+{
+ memset(__set, 0, sizeof *__set);
+ return 0;
+}
+static __inline__ int sigfillset(sigset_t * __set)
+{
+ memset(__set, ~0, sizeof *__set);
+ return 0;
+}
+static __inline__ int sigaddset(sigset_t * __set, int __signum)
+{
+ unsigned long *__lset = (unsigned long *)__set;
+ __signum--; /* Signal 0 is not in the set */
+ __lset[__signum / LONG_BIT] |= 1UL << (__signum % LONG_BIT);
+ return 0;
+}
+static __inline__ int sigdelset(sigset_t * __set, int __signum)
+{
+ unsigned long *__lset = (unsigned long *)__set;
+ __signum--; /* Signal 0 is not in the set */
+ __lset[__signum / LONG_BIT] &= ~(1UL << (__signum % LONG_BIT));
+ return 0;
+}
+static __inline__ int sigismember(sigset_t * __set, int __signum)
+{
+ unsigned long *__lset = (unsigned long *)__set;
+ __signum--; /* Signal 0 is not in the set */
+ return (int)((__lset[__signum / LONG_BIT] >> (__signum % LONG_BIT)) &
+ 1);
+}
+
+__extern __sighandler_t __signal(int, __sighandler_t, int);
+#ifndef signal
+__extern __sighandler_t signal(int, __sighandler_t);
+#endif
+__extern __sighandler_t sysv_signal(int, __sighandler_t);
+__extern __sighandler_t bsd_signal(int, __sighandler_t);
+__extern int sigaction(int, const struct sigaction *, struct sigaction *);
+__extern int sigprocmask(int, const sigset_t *, sigset_t *);
+__extern int sigpending(sigset_t *);
+__extern int sigsuspend(const sigset_t *);
+__extern int raise(int);
+__extern int kill(pid_t, int);
+
+#endif /* _SIGNAL_H */
diff --git a/usr/include/stdarg.h b/usr/include/stdarg.h
new file mode 100644
index 0000000..cc324b8
--- /dev/null
+++ b/usr/include/stdarg.h
@@ -0,0 +1,14 @@
+/*
+ * stdarg.h
+ *
+ * This is just a wrapper for the gcc one, but defines va_copy()
+ * even if gcc doesn't.
+ */
+
+/* Note: the _STDARG_H macro belongs to the gcc header... */
+#include_next <stdarg.h>
+
+/* Older gcc considers this an extension, so it's double underbar only */
+#ifndef va_copy
+#define va_copy(d,s) __va_copy(d,s)
+#endif
diff --git a/usr/include/stddef.h b/usr/include/stddef.h
new file mode 100644
index 0000000..6811451
--- /dev/null
+++ b/usr/include/stddef.h
@@ -0,0 +1,54 @@
+/*
+ * stddef.h
+ */
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#ifndef __KLIBC__
+# error "__KLIBC__ not defined, compiler invocation error!"
+#endif
+
+/*
+ * __SIZE_TYPE__ and __PTRDIFF_TYPE__ are defined by GCC and
+ * many other compilers to what types the ABI expects on the
+ * target platform for size_t and ptrdiff_t, so we use these
+ * for size_t, ssize_t, ptrdiff_t definitions, if available;
+ * fall back to unsigned long, which is correct on ILP32 and
+ * LP64 platforms (Linux does not have any others) otherwise.
+ *
+ * Note: the order "long unsigned int" precisely matches GCC.
+ */
+#ifndef __SIZE_TYPE__
+#define __SIZE_TYPE__ long unsigned int
+#endif
+
+#ifndef __PTRDIFF_TYPE__
+#define __PTRDIFF_TYPE__ long int
+#endif
+
+#define _SIZE_T
+typedef __SIZE_TYPE__ size_t;
+
+#define _PTRDIFF_T
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+#undef NULL
+#ifdef __cplusplus
+# define NULL 0
+#else
+# define NULL ((void *)0)
+#endif
+
+#undef offsetof
+#define offsetof(t,m) ((size_t)&((t *)0)->m)
+
+/*
+ * The container_of construct: if p is a pointer to member m of
+ * container class c, then return a pointer to the container of which
+ * *p is a member.
+ */
+#undef container_of
+#define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m)))
+
+#endif /* _STDDEF_H */
diff --git a/usr/include/stdint.h b/usr/include/stdint.h
new file mode 100644
index 0000000..f64f027
--- /dev/null
+++ b/usr/include/stdint.h
@@ -0,0 +1,116 @@
+/*
+ * stdint.h
+ */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+#include <bitsize/stdint.h>
+
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_fast8_t;
+typedef int64_t int_fast64_t;
+
+typedef uint8_t uint_fast8_t;
+typedef uint64_t uint_fast64_t;
+
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+#define INT8_MIN (-128)
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647-1)
+#define INT64_MIN (__INT64_C(-9223372036854775807)-1)
+
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (__INT64_C(9223372036854775807))
+
+#define UINT8_MAX (255U)
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
+
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
+
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
+
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST64_MIN INT64_MIN
+
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST64_MAX INT64_MAX
+
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#include <bitsize/stdintlimits.h>
+
+#endif
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) __INT64_C(c)
+
+#define UINT8_C(c) c ## U
+#define UINT16_C(c) c ## U
+#define UINT32_C(c) c ## U
+#define UINT64_C(c) __UINT64_C(c)
+
+#define INT_LEAST8_C(c) INT8_C(c)
+#define INT_LEAST16_C(c) INT16_C(c)
+#define INT_LEAST32_C(c) INT32_C(c)
+#define INT_LEAST64_C(c) INT64_C(c)
+
+#define UINT_LEAST8_C(c) UINT8_C(c)
+#define UINT_LEAST16_C(c) UINT16_C(c)
+#define UINT_LEAST32_C(c) UINT32_C(c)
+#define UINT_LEAST64_C(c) UINT64_C(c)
+
+#define INT_FAST8_C(c) INT8_C(c)
+#define INT_FAST64_C(c) INT64_C(c)
+
+#define UINT_FAST8_C(c) UINT8_C(c)
+#define UINT_FAST64_C(c) UINT64_C(c)
+
+#define INTMAX_C(c) INT64_C(c)
+#define UINTMAX_C(c) UINT64_C(c)
+
+#include <bitsize/stdintconst.h>
+
+#endif
+
+/* Keep the kernel from trying to define these types... */
+#define __BIT_TYPES_DEFINED__
+
+#endif /* _STDINT_H */
diff --git a/usr/include/stdio.h b/usr/include/stdio.h
new file mode 100644
index 0000000..521213d
--- /dev/null
+++ b/usr/include/stdio.h
@@ -0,0 +1,156 @@
+/*
+ * stdio.h
+ */
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#include <klibc/extern.h>
+#include <klibc/sysconfig.h>
+#include <klibc/seek.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <unistd.h>
+
+struct _IO_file {
+ int _IO_fileno; /* Underlying file descriptor */
+ _Bool _IO_eof; /* End of file flag */
+ _Bool _IO_error; /* Error flag */
+};
+typedef struct _IO_file FILE;
+
+#ifndef EOF
+# define EOF (-1)
+#endif
+
+#ifndef BUFSIZ
+# define BUFSIZ _KLIBC_BUFSIZ
+#endif
+
+enum _IO_bufmode {
+ _IONBF,
+ _IOLBF,
+ _IOFBF
+};
+#define _IONBF _IONBF
+#define _IOLBF _IOLBF
+#define _IOFBF _IOFBF
+
+/*
+ * Convert between a FILE * and a file descriptor.
+ */
+__extern FILE *stdin, *stdout, *stderr;
+
+__extern FILE *fopen(const char *, const char *);
+__extern FILE *fdopen(int, const char *);
+__extern int fclose(FILE *);
+__extern int fseek(FILE *, off_t, int);
+#define fseeko fseek
+__extern void rewind(FILE *);
+__extern int fputs(const char *, FILE *);
+__extern int fputs_unlocked(const char *, FILE *);
+__extern int puts(const char *);
+__extern int fputc(int, FILE *);
+__extern int fputc_unlocked(int, FILE *);
+#define putc(c,f) fputc((c),(f))
+#define putc_unlocked(c,f) putc((c),(f))
+#define putchar(c) fputc((c),stdout)
+#define putchar_unlocked(c) putchar(c)
+
+__extern int fgetc(FILE *);
+__extern int fgetc_unlocked(FILE *);
+__extern char *fgets(char *, int, FILE *);
+__extern char *fgets_unlocked(char *, int, FILE *);
+#define getc(f) fgetc(f)
+__extern int getc_unlocked(FILE *);
+#define getc_unlocked(f) fgetc(f)
+#define getchar() fgetc(stdin)
+#define getchar_unlocked() getchar()
+__extern int ungetc(int, FILE *);
+
+__extern int printf(const char *, ...);
+__extern int vprintf(const char *, va_list);
+__extern int fprintf(FILE *, const char *, ...);
+__extern int vfprintf(FILE *, const char *, va_list);
+__extern int sprintf(char *, const char *, ...);
+__extern int vsprintf(char *, const char *, va_list);
+__extern int snprintf(char *, size_t n, const char *, ...);
+__extern int vsnprintf(char *, size_t n, const char *, va_list);
+__extern int asprintf(char **, const char *, ...);
+__extern int vasprintf(char **, const char *, va_list);
+
+__extern int sscanf(const char *, const char *, ...);
+__extern int vsscanf(const char *, const char *, va_list);
+
+__extern void perror(const char *);
+
+__extern int rename(const char *, const char *);
+__extern int renameat(int, const char *, int, const char *);
+__extern int renameat2(int, const char *, int, const char *, unsigned int);
+
+__extern int remove(const char *);
+
+__extern size_t _fread(void *, size_t, FILE *);
+__extern size_t _fwrite(const void *, size_t, FILE *);
+__extern int fflush(FILE *);
+__extern int fflush_unlocked(FILE *);
+
+__extern size_t fread(void *, size_t, size_t, FILE *);
+__extern size_t fread_unlocked(void *, size_t, size_t, FILE *);
+__extern size_t fwrite(const void *, size_t, size_t, FILE *);
+__extern size_t fwrite_unlocked(const void *, size_t, size_t, FILE *);
+
+__extern off_t ftell(FILE *__f);
+#define ftello ftell
+
+__extern int ferror(FILE * );
+__extern int ferror_unlocked(FILE * );
+__extern int feof(FILE *);
+__extern int feof_unlocked(FILE *);
+__extern int fileno(FILE *);
+__extern int fileno_unlocked(FILE *);
+__extern void clearerr(FILE *);
+__extern void clearerr_unlocked(FILE *);
+
+#ifndef __NO_STDIO_INLINES
+__extern_inline size_t
+fread(void *__p, size_t __s, size_t __n, FILE * __f)
+{
+ return _fread(__p, __s * __n, __f) / __s;
+}
+#define fread_unlocked(p, s, n, f) fread((p), (s), (n), (f))
+
+__extern_inline size_t
+fwrite(const void *__p, size_t __s, size_t __n, FILE * __f)
+{
+ return _fwrite(__p, __s * __n, __f) / __s;
+}
+#define fwrite_unlocked(p, s, n, f) fwrite((p), (s), (n), (f))
+
+__extern_inline int fileno(FILE *__f)
+{
+ return __f->_IO_fileno;
+}
+#define fileno_unlocked(f) fileno(f)
+
+__extern_inline int ferror(FILE *__f)
+{
+ return __f->_IO_error;
+}
+#define ferror_unlocked(f) ferror(f)
+
+__extern_inline int feof(FILE *__f)
+{
+ return __f->_IO_eof;
+}
+#define feof_unlocked(f) feof(f)
+
+__extern_inline void clearerr(FILE *__f)
+{
+ __f->_IO_error = 0;
+ __f->_IO_eof = 0;
+}
+#define clearerr_unlocked(f) clearerr(f)
+#endif
+
+#endif /* _STDIO_H */
diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
new file mode 100644
index 0000000..43bb8a3
--- /dev/null
+++ b/usr/include/stdlib.h
@@ -0,0 +1,104 @@
+/*
+ * stdlib.h
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+#include <malloc.h>
+#include <fcntl.h>
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+__extern __noreturn abort(void);
+static __inline__ int abs(int __n)
+{
+ return (__n < 0) ? -__n : __n;
+}
+__extern int system(const char *string);
+__extern int atexit(void (*)(void));
+__extern int on_exit(void (*)(int, void *), void *);
+__extern int atoi(const char *);
+__extern long atol(const char *);
+__extern long long atoll(const char *);
+__extern __noreturn exit(int);
+__extern __noreturn _exit(int);
+#define _Exit _exit
+static __inline__ long labs(long __n)
+{
+ return (__n < 0L) ? -__n : __n;
+}
+
+static __inline__ long long llabs(long long __n)
+{
+ return (__n < 0LL) ? -__n : __n;
+}
+
+__extern long strtol(const char *, char **, int);
+__extern long long strtoll(const char *, char **, int);
+__extern unsigned long strtoul(const char *, char **, int);
+__extern unsigned long long strtoull(const char *, char **, int);
+
+__extern char *getenv(const char *);
+__extern int putenv(const char *);
+__extern int setenv(const char *, const char *, int);
+__extern int unsetenv(const char *);
+__extern int clearenv(void);
+
+typedef int (*__comparefunc_t) (const void *, const void *);
+__extern void *bsearch(const void *, const void *, size_t, size_t,
+ __comparefunc_t);
+__extern void qsort(void *, size_t, size_t, __comparefunc_t);
+
+__extern long jrand48(unsigned short[3]);
+__extern long mrand48(void);
+__extern long nrand48(unsigned short[3]);
+__extern long lrand48(void);
+__extern unsigned short *seed48(const unsigned short[3]);
+__extern void srand48(long);
+
+#define RAND_MAX 0x7fffffff
+static __inline__ int rand(void)
+{
+ return (int)lrand48();
+}
+static __inline__ void srand(unsigned int __s)
+{
+ srand48(__s);
+}
+static __inline__ long random(void)
+{
+ return lrand48();
+}
+static __inline__ void srandom(unsigned int __s)
+{
+ srand48(__s);
+}
+
+/* Basic PTY functions. These only work if devpts is mounted! */
+
+__extern int unlockpt(int);
+__extern char *ptsname(int);
+
+static __inline__ int posix_openpt(int __mode)
+{
+ __extern int open(const char *, int, ...);
+
+ __mode &= ~(O_CREAT | O_TMPFILE);
+ return open("/dev/ptmx", __mode);
+}
+
+static __inline__ int grantpt(int __fd)
+{
+ (void)__fd;
+ return 0; /* devpts does this all for us! */
+}
+
+__extern char *realpath(const char *, char *);
+
+#endif /* _STDLIB_H */
diff --git a/usr/include/string.h b/usr/include/string.h
new file mode 100644
index 0000000..0c8c046
--- /dev/null
+++ b/usr/include/string.h
@@ -0,0 +1,49 @@
+/*
+ * string.h
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+
+__extern void *memccpy(void *, const void *, int, size_t);
+__extern void *memchr(const void *, int, size_t);
+__extern void *memrchr(const void *, int, size_t);
+__extern int memcmp(const void *, const void *, size_t);
+__extern void *memcpy(void *, const void *, size_t);
+__extern void *memmove(void *, const void *, size_t);
+__extern void *memset(void *, int, size_t);
+__extern void *memmem(const void *, size_t, const void *, size_t);
+__extern void memswap(void *, void *, size_t);
+__extern void bzero(void *, size_t);
+__extern int strcasecmp(const char *, const char *);
+__extern int strncasecmp(const char *, const char *, size_t);
+__extern char *strcat(char *, const char *);
+__extern char *strchr(const char *, int);
+__extern char *index(const char *, int);
+__extern char *strrchr(const char *, int);
+__extern char *rindex(const char *, int);
+__extern int strcmp(const char *, const char *);
+__extern char *strcpy(char *, const char *);
+__extern size_t strcspn(const char *, const char *);
+__extern char *strdup(const char *);
+__extern char *strndup(const char *, size_t);
+__extern char *strerror(int);
+__extern char *strsignal(int);
+__extern size_t strlen(const char *);
+__extern size_t strnlen(const char *, size_t);
+__extern char *strncat(char *, const char *, size_t);
+__extern size_t strlcat(char *, const char *, size_t);
+__extern int strncmp(const char *, const char *, size_t);
+__extern char *strncpy(char *, const char *, size_t);
+__extern size_t strlcpy(char *, const char *, size_t);
+__extern char *strpbrk(const char *, const char *);
+__extern char *strsep(char **, const char *);
+__extern size_t strspn(const char *, const char *);
+__extern char *strstr(const char *, const char *);
+__extern char *strtok(char *, const char *);
+__extern char *strtok_r(char *, const char *, char **);
+
+#endif /* _STRING_H */
diff --git a/usr/include/sys/auxv.h b/usr/include/sys/auxv.h
new file mode 100644
index 0000000..fc98ed4
--- /dev/null
+++ b/usr/include/sys/auxv.h
@@ -0,0 +1,17 @@
+#ifndef _SYS_AUXV_H
+#define _SYS_AUXV_H
+
+#include <klibc/compiler.h>
+#include <klibc/extern.h>
+#include <elf.h>
+
+#define _AUXVAL_MAX AT_SYSINFO_EHDR
+
+__extern unsigned long __auxval[_AUXVAL_MAX];
+
+__static_inline unsigned long getauxval(unsigned long __t)
+{
+ return (__t >= _AUXVAL_MAX) ? 0 : __auxval[__t];
+}
+
+#endif /* _SYS_AUXV_H */
diff --git a/usr/include/sys/capability.h b/usr/include/sys/capability.h
new file mode 100644
index 0000000..8b92984
--- /dev/null
+++ b/usr/include/sys/capability.h
@@ -0,0 +1,11 @@
+#ifndef _SYS_CAPABILITY_H
+#define _SYS_CAPABILITY_H
+
+#include <sys/types.h>
+#include <klibc/extern.h>
+#include <linux/capability.h>
+
+__extern int capget(cap_user_header_t, cap_user_data_t);
+__extern int capset(cap_user_header_t, const cap_user_data_t);
+
+#endif /* _SYS_CAPABILITY_H */
diff --git a/usr/include/sys/dirent.h b/usr/include/sys/dirent.h
new file mode 100644
index 0000000..18b7a33
--- /dev/null
+++ b/usr/include/sys/dirent.h
@@ -0,0 +1,32 @@
+/*
+ * sys/dirent.h
+ */
+
+#ifndef _SYS_DIRENT_H
+#define _SYS_DIRENT_H
+
+#include <stdint.h>
+
+/* The kernel calls this struct dirent64 */
+struct dirent {
+ uint64_t d_ino;
+ int64_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
+
+/* File types to use for d_type */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+__extern int getdents(unsigned int, struct dirent *, unsigned int);
+
+#endif /* _SYS_DIRENT_H */
diff --git a/usr/include/sys/elf32.h b/usr/include/sys/elf32.h
new file mode 100644
index 0000000..6da2ddb
--- /dev/null
+++ b/usr/include/sys/elf32.h
@@ -0,0 +1,117 @@
+/*
+ * sys/elf32.h
+ */
+
+#ifndef _SYS_ELF32_H
+#define _SYS_ELF32_H
+
+#include <sys/elfcommon.h>
+
+/* ELF standard typedefs (yet more proof that <stdint.h> was way overdue) */
+typedef uint16_t Elf32_Half;
+typedef int16_t Elf32_SHalf;
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+
+typedef uint32_t Elf32_Off;
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Section;
+
+/* Dynamic header */
+
+typedef struct elf32_dyn {
+ Elf32_Sword d_tag;
+ union {
+ Elf32_Sword d_val;
+ Elf32_Addr d_ptr;
+ } d_un;
+} Elf32_Dyn;
+
+/* Relocations */
+
+#define ELF32_R_SYM(x) ((x) >> 8)
+#define ELF32_R_TYPE(x) ((x) & 0xff)
+
+typedef struct elf32_rel {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+} Elf32_Rel;
+
+typedef struct elf32_rela {
+ Elf32_Addr r_offset;
+ Elf32_Word r_info;
+ Elf32_Sword r_addend;
+} Elf32_Rela;
+
+/* Symbol */
+
+typedef struct elf32_sym {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+} Elf32_Sym;
+
+/* Main file header */
+
+typedef struct elf32_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+/* Program header */
+
+typedef struct elf32_phdr {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+/* Section header */
+
+typedef struct elf32_shdr {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+/* Note header */
+typedef struct elf32_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+/* How to extract and insert information held in the st_info field. */
+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val) & 0xf)
+
+#endif /* _SYS_ELF32_H */
diff --git a/usr/include/sys/elf64.h b/usr/include/sys/elf64.h
new file mode 100644
index 0000000..877b7cd
--- /dev/null
+++ b/usr/include/sys/elf64.h
@@ -0,0 +1,117 @@
+/*
+ * sys/elf64.h
+ */
+
+#ifndef _SYS_ELF64_H
+#define _SYS_ELF64_H
+
+#include <sys/elfcommon.h>
+
+/* ELF standard typedefs (yet more proof that <stdint.h> was way overdue) */
+typedef uint16_t Elf64_Half;
+typedef int16_t Elf64_SHalf;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+typedef uint64_t Elf64_Off;
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Section;
+
+/* Dynamic header */
+
+typedef struct elf64_dyn {
+ Elf64_Sxword d_tag;
+ union {
+ Elf64_Xword d_val;
+ Elf64_Addr d_ptr;
+ } d_un;
+} Elf64_Dyn;
+
+/* Relocations */
+
+#define ELF64_R_SYM(x) ((x) >> 32)
+#define ELF64_R_TYPE(x) ((x) & 0xffffffff)
+
+typedef struct elf64_rel {
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+} Elf64_Rel;
+
+typedef struct elf64_rela {
+ Elf64_Addr r_offset;
+ Elf64_Xword r_info;
+ Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+/* Symbol */
+
+typedef struct elf64_sym {
+ Elf64_Word st_name;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf64_Half st_shndx;
+ Elf64_Addr st_value;
+ Elf64_Xword st_size;
+} Elf64_Sym;
+
+/* Main file header */
+
+typedef struct elf64_hdr {
+ unsigned char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry;
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* Program header */
+
+typedef struct elf64_phdr {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Addr p_paddr;
+ Elf64_Xword p_filesz;
+ Elf64_Xword p_memsz;
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+/* Section header */
+
+typedef struct elf64_shdr {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Xword sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Xword sh_addralign;
+ Elf64_Xword sh_entsize;
+} Elf64_Shdr;
+
+/* Note header */
+typedef struct elf64_note {
+ Elf64_Word n_namesz; /* Name size */
+ Elf64_Word n_descsz; /* Content size */
+ Elf64_Word n_type; /* Content type */
+} Elf64_Nhdr;
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
+
+#endif /* _SYS_ELF64_H */
diff --git a/usr/include/sys/elfcommon.h b/usr/include/sys/elfcommon.h
new file mode 100644
index 0000000..603b0ce
--- /dev/null
+++ b/usr/include/sys/elfcommon.h
@@ -0,0 +1,202 @@
+/*
+ * sys/elfcommon.h
+ */
+
+#ifndef _SYS_ELFCOMMON_H
+#define _SYS_ELFCOMMON_H
+
+#include <stdint.h>
+
+/* Segment types */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOOS 0x60000000
+#define PT_HIOS 0x6fffffff
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+#define PT_GNU_EH_FRAME 0x6474e550 /* Extension, eh? */
+
+/* ELF file types */
+#define ET_NONE 0
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+#define ET_LOPROC 0xff00
+#define ET_HIPROC 0xffff
+
+/* ELF machine types */
+#define EM_NONE 0
+#define EM_M32 1
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_68K 4
+#define EM_88K 5
+#define EM_486 6 /* Not used in Linux at least */
+#define EM_860 7
+#define EM_MIPS 8 /* R3k, bigendian(?) */
+#define EM_MIPS_RS4_BE 10 /* R4k BE */
+#define EM_PARISC 15
+#define EM_SPARC32PLUS 18
+#define EM_PPC 20
+#define EM_PPC64 21
+#define EM_S390 22
+#define EM_SH 42
+#define EM_SPARCV9 43 /* v9 = SPARC64 */
+#define EM_H8_300H 47
+#define EM_H8S 48
+#define EM_IA_64 50 /* Itanic */
+#define EM_X86_64 62
+#define EM_CRIS 76
+#define EM_V850 87
+#define EM_ALPHA 0x9026 /* Interrim Alpha that stuck around */
+#define EM_CYGNUS_V850 0x9080 /* Old v850 ID used by Cygnus */
+#define EM_S390_OLD 0xA390 /* Obsolete interrim value for S/390 */
+
+/* Dynamic type values */
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
+
+/* Auxilliary table entries */
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_NOTELF 10 /* program is not ELF */
+#define AT_UID 11 /* real uid */
+#define AT_EUID 12 /* effective uid */
+#define AT_GID 13 /* real gid */
+#define AT_EGID 14 /* effective gid */
+#define AT_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
+#define AT_CLKTCK 17 /* frequency at which times() increments */
+/* 18..22 = ? */
+#define AT_SECURE 23 /* secure mode boolean */
+#define AT_SYSINFO 32 /* vdso entry point address */
+#define AT_SYSINFO_EHDR 33 /* vdso header address */
+
+/* Program header permission flags */
+#define PF_X 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+
+/* Section header types */
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_NUM 12
+#define SHT_LOPROC 0x70000000
+#define SHT_HIPROC 0x7fffffff
+#define SHT_LOUSER 0x80000000
+#define SHT_HIUSER 0xffffffff
+
+/* Section header flags */
+#define SHF_WRITE 0x1
+#define SHF_ALLOC 0x2
+#define SHF_EXECINSTR 0x4
+#define SHF_MASKPROC 0xf0000000
+
+/* Special section numbers */
+#define SHN_UNDEF 0
+#define SHN_LORESERVE 0xff00
+#define SHN_LOPROC 0xff00
+#define SHN_HIPROC 0xff1f
+#define SHN_ABS 0xfff1
+#define SHN_COMMON 0xfff2
+#define SHN_HIRESERVE 0xffff
+
+/* End of a chain. */
+#define STN_UNDEF 0
+
+/* Lenght of magic at the start of a file */
+#define EI_NIDENT 16
+
+/* Magic number constants... */
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_PAD 8
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define ELFCLASSNONE 0 /* EI_CLASS */
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+#define ELFCLASSNUM 3
+
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+#define EV_NONE 0 /* e_version, EI_VERSION */
+#define EV_CURRENT 1
+#define EV_NUM 2
+
+#define ELFOSABI_NONE 0
+#define ELFOSABI_LINUX 3
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+#endif /* _SYS_ELFCOMMON_H */
diff --git a/usr/include/sys/file.h b/usr/include/sys/file.h
new file mode 100644
index 0000000..7b580f3
--- /dev/null
+++ b/usr/include/sys/file.h
@@ -0,0 +1,9 @@
+#ifndef _SYS_FILE_H
+#define _SYS_FILE_H
+
+/* LOCK_ definitions */
+#include <fcntl.h>
+
+__extern int flock(int, int);
+
+#endif /* _SYS_FILE_H */
diff --git a/usr/include/sys/fsuid.h b/usr/include/sys/fsuid.h
new file mode 100644
index 0000000..d64e28b
--- /dev/null
+++ b/usr/include/sys/fsuid.h
@@ -0,0 +1,14 @@
+/*
+ * sys/fsuid.h
+ */
+
+#ifndef _SYS_FSUID_H
+#define _SYS_FSUID_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+
+__extern int setfsuid(uid_t);
+__extern int setfsgid(gid_t);
+
+#endif /* _SYS_FSUID_H */
diff --git a/usr/include/sys/inotify.h b/usr/include/sys/inotify.h
new file mode 100644
index 0000000..e08cb05
--- /dev/null
+++ b/usr/include/sys/inotify.h
@@ -0,0 +1,16 @@
+/*
+ * sys/inotify.h
+ */
+
+#ifndef _SYS_INOTIFY_H
+#define _SYS_INOTIFY_H
+
+#include <sys/types.h>
+#include <linux/inotify.h>
+#include <klibc/extern.h>
+
+__extern int inotify_init(void);
+__extern int inotify_add_watch(int, const char *, __u32);
+__extern int inotify_rm_watch(int, __u32);
+
+#endif /* _SYS_INOTIFY_H */
diff --git a/usr/include/sys/ioctl.h b/usr/include/sys/ioctl.h
new file mode 100644
index 0000000..7b0b687
--- /dev/null
+++ b/usr/include/sys/ioctl.h
@@ -0,0 +1,18 @@
+/*
+ * sys/ioctl.h
+ */
+
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_H
+
+#include <sys/types.h>
+#include <klibc/extern.h>
+#include <linux/ioctl.h>
+#include <asm/ioctls.h>
+
+/* the SIOCxxx I/O are hidden */
+#include <linux/sockios.h>
+
+__extern int ioctl(int, int, void *);
+
+#endif /* _SYS_IOCTL_H */
diff --git a/usr/include/sys/klog.h b/usr/include/sys/klog.h
new file mode 100644
index 0000000..02c7217
--- /dev/null
+++ b/usr/include/sys/klog.h
@@ -0,0 +1,24 @@
+/*
+ * sys/klog.h
+ */
+
+#ifndef _SYS_KLOG_H
+#define _SYS_KLOG_H
+
+#include <klibc/extern.h>
+
+#define KLOG_CLOSE 0
+#define KLOG_OPEN 1
+#define KLOG_READ 2
+#define KLOG_READ_ALL 3
+#define KLOG_READ_CLEAR 4
+#define KLOG_CLEAR 5
+#define KLOG_DISABLE 6
+#define KLOG_ENABLE 7
+#define KLOG_SETLEVEL 8
+#define KLOG_UNREADSIZE 9
+#define KLOG_WRITE 10
+
+__extern int klogctl(int, char *, int);
+
+#endif /* _SYS_KLOG_H */
diff --git a/usr/include/sys/md.h b/usr/include/sys/md.h
new file mode 100644
index 0000000..63be3d8
--- /dev/null
+++ b/usr/include/sys/md.h
@@ -0,0 +1,34 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * sys/md.h
+ *
+ * Defines for the Linux md functionality. Some of this stuff is
+ * userspace-visible but lives in md_k.h, which is user-space unsafe.
+ * Sigh.
+ */
+
+#ifndef _SYS_MD_H
+#define _SYS_MD_H
+
+#include <sys/types.h>
+
+#define LEVEL_MULTIPATH (-4)
+#define LEVEL_LINEAR (-1)
+#define LEVEL_FAULTY (-5)
+#define MAX_MD_DEVS 256 /* Max number of md dev */
+
+#include <linux/raid/md_u.h>
+#include <linux/raid/md_p.h>
+
+#endif /* _SYS_MD_H */
diff --git a/usr/include/sys/mman.h b/usr/include/sys/mman.h
new file mode 100644
index 0000000..3fd626e
--- /dev/null
+++ b/usr/include/sys/mman.h
@@ -0,0 +1,26 @@
+/*
+ * sys/mman.h
+ */
+
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/mman.h>
+
+#define MAP_FAILED ((void *)-1)
+
+__extern void *mmap(void *, size_t, int, int, int, off_t);
+__extern int munmap(void *, size_t);
+__extern void *mremap(void *, size_t, size_t, unsigned long);
+__extern int shm_open(const char *, int, mode_t);
+__extern int shm_unlink(const char *);
+__extern int msync(const void *, size_t, int);
+__extern int mprotect(const void *, size_t, int);
+__extern int mlockall(int);
+__extern int munlockall(void);
+__extern int mlock(const void *, size_t);
+__extern int munlock(const void *, size_t);
+
+#endif /* _SYS_MMAN_H */
diff --git a/usr/include/sys/mount.h b/usr/include/sys/mount.h
new file mode 100644
index 0000000..9d6b0ee
--- /dev/null
+++ b/usr/include/sys/mount.h
@@ -0,0 +1,71 @@
+/*
+ * sys/mount.h
+ */
+
+#ifndef _SYS_MOUNT_H
+#define _SYS_MOUNT_H
+
+#include <klibc/extern.h>
+#include <sys/ioctl.h>
+
+/*
+ * These are the fs-independent mount-flags: up to 32 flags are supported
+ */
+#define MS_RDONLY 0x0001 /* Mount read-only */
+#define MS_NOSUID 0x0002 /* Ignore suid and sgid bits */
+#define MS_NODEV 0x0004 /* Disallow access to device special files */
+#define MS_NOEXEC 0x0008 /* Disallow program execution */
+#define MS_SYNCHRONOUS 0x0010 /* Writes are synced at once */
+#define MS_REMOUNT 0x0020 /* Alter flags of a mounted FS */
+#define MS_MANDLOCK 0x0040 /* Allow mandatory locks on an FS */
+#define MS_DIRSYNC 0x0080 /* Directory modifications are synchronous */
+#define MS_NOATIME 0x0400 /* Do not update access times. */
+#define MS_NODIRATIME 0x0800 /* Do not update directory access times */
+#define MS_BIND 0x1000
+#define MS_MOVE 0x2000
+#define MS_REC 0x4000
+#define MS_VERBOSE 0x8000
+#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */
+#define MS_ONE_SECOND (1<<17) /* fs has 1 sec a/m/ctime resolution */
+#define MS_ACTIVE (1<<30)
+#define MS_NOUSER (1<<31)
+
+/*
+ * Superblock flags that can be altered by MS_REMOUNT
+ */
+#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+
+/*
+ * Old magic mount flag and mask
+ */
+#define MS_MGC_VAL 0xC0ED0000
+#define MS_MGC_MSK 0xffff0000
+
+/*
+ * umount2() flags
+ */
+#define MNT_FORCE 1 /* Forcibly unmount */
+#define MNT_DETACH 2 /* Detach from tree only */
+#define MNT_EXPIRE 4 /* Mark for expiry */
+
+/*
+ * Block device ioctls
+ */
+#define BLKROSET _IO(0x12, 93) /* Set device read-only (0 = read-write). */
+#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
+#define BLKRRPART _IO(0x12, 95) /* Re-read partition table. */
+#define BLKGETSIZE _IO(0x12, 96) /* Return device size. */
+#define BLKFLSBUF _IO(0x12, 97) /* Flush buffer cache. */
+#define BLKRASET _IO(0x12, 98) /* Set read ahead for block device. */
+#define BLKRAGET _IO(0x12, 99) /* Get current read ahead setting. */
+
+/*
+ * Prototypes
+ */
+__extern int mount(const char *, const char *,
+ const char *, unsigned long, const void *);
+__extern int umount(const char *);
+__extern int umount2(const char *, int);
+__extern int pivot_root(const char *, const char *);
+
+#endif /* _SYS_MOUNT_H */
diff --git a/usr/include/sys/param.h b/usr/include/sys/param.h
new file mode 100644
index 0000000..fb3b2e4
--- /dev/null
+++ b/usr/include/sys/param.h
@@ -0,0 +1,11 @@
+/*
+ * sys/param.h
+ */
+
+#ifndef _SYS_PARAM_H
+#define _SYS_PARAM_H
+
+#include <limits.h>
+#include <linux/param.h>
+
+#endif /* _SYS_PARAM_H */
diff --git a/usr/include/sys/poll.h b/usr/include/sys/poll.h
new file mode 100644
index 0000000..f0c60c2
--- /dev/null
+++ b/usr/include/sys/poll.h
@@ -0,0 +1,20 @@
+/*
+ * poll.h
+ */
+
+#ifndef _POLL_H
+#define _POLL_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <linux/poll.h>
+
+/* POSIX specifies "int" for the timeout, Linux seems to use long... */
+
+typedef unsigned int nfds_t;
+__extern int poll(struct pollfd *, nfds_t, long);
+__extern int ppoll(struct pollfd *, nfds_t, struct timespec *,
+ const sigset_t *);
+
+#endif /* _POLL_H */
diff --git a/usr/include/sys/prctl.h b/usr/include/sys/prctl.h
new file mode 100644
index 0000000..b0f41f5
--- /dev/null
+++ b/usr/include/sys/prctl.h
@@ -0,0 +1,11 @@
+#ifndef _SYS_PRCTL_H
+#define _SYS_PRCTL_H
+
+#include <sys/types.h>
+#include <klibc/extern.h>
+#include <linux/prctl.h>
+
+/* glibc has this as a varadic function, so join the club... */
+__extern int prctl(int, ...);
+
+#endif /* _SYS_PRCTL_H */
diff --git a/usr/include/sys/reboot.h b/usr/include/sys/reboot.h
new file mode 100644
index 0000000..b46a1c5
--- /dev/null
+++ b/usr/include/sys/reboot.h
@@ -0,0 +1,25 @@
+/*
+ * sys/reboot.h
+ */
+
+#ifndef _SYS_REBOOT_H
+#define _SYS_REBOOT_H
+
+#include <klibc/extern.h>
+#include <linux/reboot.h>
+
+/* glibc names these constants differently; allow both versions */
+
+#define RB_AUTOBOOT LINUX_REBOOT_CMD_RESTART
+#define RB_HALT_SYSTEM LINUX_REBOOT_CMD_HALT
+#define RB_ENABLE_CAD LINUX_REBOOT_CMD_CAD_ON
+#define RB_DISABLE_CAD LINUX_REBOOT_CMD_CAD_OFF
+#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
+
+/* two-arguments version of reboot */
+__extern int reboot(int, void *);
+
+/* Native four-argument system call */
+__extern int __reboot(int, int, int, void *);
+
+#endif /* _SYS_REBOOT_H */
diff --git a/usr/include/sys/resource.h b/usr/include/sys/resource.h
new file mode 100644
index 0000000..e43a69d
--- /dev/null
+++ b/usr/include/sys/resource.h
@@ -0,0 +1,48 @@
+/*
+ * sys/resource.h
+ */
+
+#ifndef _SYS_RESOURCE_H
+#define _SYS_RESOURCE_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN (-1)
+#define RUSAGE_BOTH (-2)
+#define RUSAGE_THREAD 1
+
+struct rusage {
+ struct timeval_old ru_utime; /* user time used */
+ struct timeval_old ru_stime; /* system time used */
+ __kernel_long_t ru_maxrss; /* maximum resident set size */
+ __kernel_long_t ru_ixrss; /* integral shared memory size */
+ __kernel_long_t ru_idrss; /* integral unshared data size */
+ __kernel_long_t ru_isrss; /* integral unshared stack size */
+ __kernel_long_t ru_minflt; /* page reclaims */
+ __kernel_long_t ru_majflt; /* page faults */
+ __kernel_long_t ru_nswap; /* swaps */
+ __kernel_long_t ru_inblock; /* block input operations */
+ __kernel_long_t ru_oublock; /* block output operations */
+ __kernel_long_t ru_msgsnd; /* messages sent */
+ __kernel_long_t ru_msgrcv; /* messages received */
+ __kernel_long_t ru_nsignals; /* signals received */
+ __kernel_long_t ru_nvcsw; /* voluntary context switches */
+ __kernel_long_t ru_nivcsw; /* involuntary " */
+};
+
+#define PRIO_MIN (-20)
+#define PRIO_MAX 20
+
+#define PRIO_PROCESS 0
+#define PRIO_PGRP 1
+#define PRIO_USER 2
+
+__extern int getpriority(int, int);
+__extern int setpriority(int, int, int);
+
+__extern int getrusage(int, struct rusage *);
+
+#endif /* _SYS_RESOURCE_H */
diff --git a/usr/include/sys/select.h b/usr/include/sys/select.h
new file mode 100644
index 0000000..cc4e00e
--- /dev/null
+++ b/usr/include/sys/select.h
@@ -0,0 +1,17 @@
+/*
+ * sys/select.h
+ */
+
+#ifndef _SYS_SELECT_H
+#define _SYS_SELECT_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+
+__extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+__extern int pselect(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const sigset_t *);
+
+#endif /* _SYS_SELECT_H */
diff --git a/usr/include/sys/sendfile.h b/usr/include/sys/sendfile.h
new file mode 100644
index 0000000..a745f10
--- /dev/null
+++ b/usr/include/sys/sendfile.h
@@ -0,0 +1,14 @@
+/*
+ * sys/sendfile.h
+ */
+
+#ifndef _SYS_SENDFILE_H
+#define _SYS_SENDFILE_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+__extern ssize_t sendfile(int, int, off_t *, size_t, off_t);
+
+#endif /* _SYS_SENDFILE_H */
diff --git a/usr/include/sys/socket.h b/usr/include/sys/socket.h
new file mode 100644
index 0000000..d0ba9eb
--- /dev/null
+++ b/usr/include/sys/socket.h
@@ -0,0 +1,270 @@
+/*
+ * sys/socket.h
+ */
+
+#ifndef _SYS_SOCKET_H
+#define _SYS_SOCKET_H
+
+#include <sys/types.h>
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <klibc/sysconfig.h>
+#include <linux/socket.h>
+#include <linux/uio.h>
+#include <asm/socket.h>
+#if _KLIBC_HAS_ARCHSOCKET_H
+#include <klibc/archsocket.h>
+#endif
+
+/* Great job, guys! These are *architecture-specific* ABI constants,
+ that are hidden under #ifdef __KERNEL__... what a brilliant idea!
+ These are the "common" definitions; if not appropriate, override
+ them in <klibc/archsocket.h>. */
+
+#ifndef SOCK_STREAM
+# define SOCK_STREAM 1
+# define SOCK_DGRAM 2
+# define SOCK_RAW 3
+# define SOCK_RDM 4
+# define SOCK_SEQPACKET 5
+# define SOCK_PACKET 10
+# define SOCK_CLOEXEC 02000000
+# define SOCK_NONBLOCK 04000
+#endif
+
+/* The maximum backlock queue length. */
+#define SOMAXCONN 128
+
+#ifndef AF_INET
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* AppleTalk DDP */
+#define AF_NETROM 6 /* Amateur Radio NET/ROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_ATMPVC 8 /* ATM PVCs */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
+#define AF_DECnet 12 /* Reserved for DECnet project */
+#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
+#define AF_SECURITY 14 /* Security callback pseudo AF */
+#define AF_KEY 15 /* PF_KEY key management API */
+#define AF_NETLINK 16
+#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
+#define AF_PACKET 17 /* Packet family */
+#define AF_ASH 18 /* Ash */
+#define AF_ECONET 19 /* Acorn Econet */
+#define AF_ATMSVC 20 /* ATM SVCs */
+#define AF_RDS 21 /* RDS sockets */
+#define AF_SNA 22 /* Linux SNA Project (nutters!) */
+#define AF_IRDA 23 /* IRDA sockets */
+#define AF_PPPOX 24 /* PPPoX sockets */
+#define AF_WANPIPE 25 /* Wanpipe API Sockets */
+#define AF_LLC 26 /* Linux LLC */
+#define AF_CAN 29 /* Controller Area Network */
+#define AF_TIPC 30 /* TIPC sockets */
+#define AF_BLUETOOTH 31 /* Bluetooth sockets */
+#define AF_IUCV 32 /* IUCV sockets */
+#define AF_RXRPC 33 /* RxRPC sockets */
+#define AF_ISDN 34 /* mISDN sockets */
+#define AF_PHONET 35 /* Phonet sockets */
+#define AF_IEEE802154 36 /* IEEE802154 sockets */
+#define AF_MAX 37 /* For now.. */
+#endif // !AF_INET
+
+#ifndef PF_UNSPEC
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_LOCAL AF_LOCAL
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_ATMPVC AF_ATMPVC
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+#define PF_ROSE AF_ROSE
+#define PF_DECnet AF_DECnet
+#define PF_NETBEUI AF_NETBEUI
+#define PF_SECURITY AF_SECURITY
+#define PF_KEY AF_KEY
+#define PF_NETLINK AF_NETLINK
+#define PF_ROUTE AF_ROUTE
+#define PF_PACKET AF_PACKET
+#define PF_ASH AF_ASH
+#define PF_ECONET AF_ECONET
+#define PF_ATMSVC AF_ATMSVC
+#define PF_RDS AF_RDS
+#define PF_SNA AF_SNA
+#define PF_IRDA AF_IRDA
+#define PF_PPPOX AF_PPPOX
+#define PF_WANPIPE AF_WANPIPE
+#define PF_LLC AF_LLC
+#define PF_CAN AF_CAN
+#define PF_TIPC AF_TIPC
+#define PF_BLUETOOTH AF_BLUETOOTH
+#define PF_IUCV AF_IUCV
+#define PF_RXRPC AF_RXRPC
+#define PF_ISDN AF_ISDN
+#define PF_PHONET AF_PHONET
+#define PF_IEEE802154 AF_IEEE802154
+#define PF_MAX AF_MAX
+#endif // !PF_UNSPEC
+
+#ifndef MSG_OOB
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */
+#define MSG_CTRUNC 8
+#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40 /* Nonblocking io */
+#define MSG_EOR 0x80 /* End of record */
+#define MSG_WAITALL 0x100 /* Wait for a full request */
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800 /* Confirm path validity */
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */
+#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
+#define MSG_MORE 0x8000 /* Sender will send more */
+
+#define MSG_EOF MSG_FIN
+
+#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exit for file
+ descriptor received through
+ SCM_RIGHTS */
+#if defined(CONFIG_COMPAT)
+#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
+#else
+#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
+#endif
+#endif // !MSG_OOB
+
+/* These types is hidden under __KERNEL__ in kernel sources */
+typedef unsigned short sa_family_t;
+struct sockaddr {
+ sa_family_t sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+typedef int socklen_t;
+struct msghdr {
+ void *msg_name;
+ int msg_namelen;
+ struct iovec *msg_iov;
+ size_t msg_iovlen;
+ void *msg_control;
+ size_t msg_controllen;
+ unsigned msg_flags;
+};
+
+/* Ancillary data structures and cmsg macros are also hidden under __KERNEL__ */
+#ifndef CMSG_FIRSTHDR
+/*
+ * POSIX 1003.1g - ancillary data object information
+ * Ancillary data consits of a sequence of pairs of
+ * (cmsghdr, cmsg_data[])
+ */
+
+struct cmsghdr {
+ __kernel_size_t cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+};
+
+/*
+ * Ancilliary data object information MACROS
+ * Table 5-14 of POSIX 1003.1g
+ */
+
+#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+
+#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
+
+#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
+ (struct cmsghdr *)(ctl) : \
+ (struct cmsghdr *)NULL)
+#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+ (cmsg)->cmsg_len <= (unsigned long) \
+ ((mhdr)->msg_controllen - \
+ ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
+
+/*
+ * Get the next cmsg header
+ *
+ * PLEASE, do not touch this function. If you think, that it is
+ * incorrect, grep kernel sources and think about consequences
+ * before trying to improve it.
+ *
+ * Now it always returns valid, not truncated ancillary object
+ * HEADER. But caller still MUST check, that cmsg->cmsg_len is
+ * inside range, given by msg->msg_controllen before using
+ * ancillary object DATA. --ANK (980731)
+ */
+
+static inline struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr *__cmsg)
+{
+ struct cmsghdr * __ptr;
+
+ __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return (struct cmsghdr *)0;
+
+ return __ptr;
+}
+
+static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+ return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+/* "Socket"-level control message types: */
+
+#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
+#define SCM_SECURITY 0x03 /* rw: security label */
+
+struct ucred {
+ __u32 pid;
+ __u32 uid;
+ __u32 gid;
+};
+#endif /* CMSG_FIRSTHDR */
+
+
+__extern int socket(int, int, int);
+__extern int bind(int, const struct sockaddr *, int);
+__extern int connect(int, const struct sockaddr *, socklen_t);
+__extern int listen(int, int);
+__extern int accept(int, struct sockaddr *, socklen_t *);
+__extern int accept4(int, struct sockaddr *, socklen_t *, int);
+__extern int getsockname(int, struct sockaddr *, socklen_t *);
+__extern int getpeername(int, struct sockaddr *, socklen_t *);
+__extern int socketpair(int, int, int, int *);
+__extern int send(int, const void *, size_t, unsigned int);
+__extern int sendto(int, const void *, size_t, int, const struct sockaddr *,
+ socklen_t);
+__extern int recv(int, void *, size_t, unsigned int);
+__extern int recvfrom(int, void *, size_t, unsigned int, struct sockaddr *,
+ socklen_t *);
+__extern int shutdown(int, int);
+__extern int setsockopt(int, int, int, const void *, socklen_t);
+__extern int getsockopt(int, int, int, void *, socklen_t *);
+__extern int sendmsg(int, const struct msghdr *, unsigned int);
+__extern int recvmsg(int, struct msghdr *, unsigned int);
+
+#endif /* _SYS_SOCKET_H */
diff --git a/usr/include/sys/splice.h b/usr/include/sys/splice.h
new file mode 100644
index 0000000..1fa26d9
--- /dev/null
+++ b/usr/include/sys/splice.h
@@ -0,0 +1,19 @@
+/*
+ * sys/splice.h
+ */
+
+#ifndef _SYS_SPLICE_H
+#define _SYS_SPLICE_H
+
+/* move pages instead of copying */
+#define SPLICE_F_MOVE 1
+/* don't block on the pipe splicing (but we may still block on the fd
+ we splice from/to, of course */
+#define SPLICE_F_NONBLOCK 2
+/* expect more data */
+#define SPLICE_F_MORE 4
+
+__extern int splice(int, off_t *, int, off_t *, size_t, unsigned int);
+__extern int tee(int, int, size_t, unsigned int);
+
+#endif /* _SYS_SPLICE_H */
diff --git a/usr/include/sys/stat.h b/usr/include/sys/stat.h
new file mode 100644
index 0000000..861b462
--- /dev/null
+++ b/usr/include/sys/stat.h
@@ -0,0 +1,96 @@
+/*
+ * sys/stat.h
+ */
+
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <sys/time.h> /* For struct timespec */
+#include <linux/stat.h>
+
+/* 2.6.21 kernels have once again hidden a bunch of stuff... */
+#ifndef S_IFMT
+
+#define S_IFMT 00170000
+#define S_IFSOCK 0140000
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#endif
+
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+
+/* struct stat with 64-bit time, not used by kernel UAPI */
+struct stat {
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ unsigned int st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ int st_blksize;
+ off_t st_blocks;
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+};
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+
+__extern int stat(const char *, struct stat *);
+__extern int fstat(int, struct stat *);
+__extern int fstatat(int, const char *, struct stat *, int);
+__extern int lstat(const char *, struct stat *);
+__extern int statx(int, const char *, int, unsigned int, struct statx *);
+__extern mode_t umask(mode_t);
+__extern int mknod(const char *, mode_t, dev_t);
+__extern int mknodat(int, const char *, mode_t, dev_t);
+__extern int mkfifo(const char *, mode_t);
+__extern int utimensat(int, const char *, const struct timespec *, int);
+__extern int fchmodat(int, const char *, mode_t, int);
+
+__extern_inline int mkfifo(const char *__p, mode_t __m)
+{
+ return mknod(__p, (__m & ~S_IFMT) | S_IFIFO, (dev_t) 0);
+}
+
+#endif /* _SYS_STAT_H */
diff --git a/usr/include/sys/statfs.h b/usr/include/sys/statfs.h
new file mode 100644
index 0000000..53b3b5e
--- /dev/null
+++ b/usr/include/sys/statfs.h
@@ -0,0 +1 @@
+#include <sys/vfs.h>
diff --git a/usr/include/sys/syscall.h b/usr/include/sys/syscall.h
new file mode 100644
index 0000000..8fe0142
--- /dev/null
+++ b/usr/include/sys/syscall.h
@@ -0,0 +1,13 @@
+/*
+ * sys/syscall.h
+ *
+ * Generic system call interface macros
+ */
+#ifndef _SYS_SYSCALL_H
+#define _SYS_SYSCALL_H
+
+#include <errno.h>
+#include <sys/types.h>
+#include <asm/unistd.h>
+
+#endif /* _SYS_SYSCALL_H */
diff --git a/usr/include/sys/sysconf.h b/usr/include/sys/sysconf.h
new file mode 100644
index 0000000..13ababc
--- /dev/null
+++ b/usr/include/sys/sysconf.h
@@ -0,0 +1,40 @@
+/*
+ * sys/sysconf.h
+ *
+ * sysconf() macros and demultiplex
+ * This file is included in <unistd.h>
+ *
+ * Add things here as needed, we don't really want to add things wildly.
+ * For things that require a lot of code, create an out-of-line function
+ * and put it in a .c file in the sysconf directory.
+ */
+
+#ifndef _SYS_SYSCONF_H
+#define _SYS_SYSCONF_H
+
+#ifndef _UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+
+enum sysconf {
+ _SC_PAGESIZE = 1,
+};
+
+__extern long sysconf(int);
+
+__must_inline long __sysconf_inline(int __val)
+{
+ switch (__val) {
+ case _SC_PAGESIZE:
+ return getpagesize();
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+#define sysconf(x) \
+ (__builtin_constant_p(x) ? __sysconf_inline(x) : sysconf(x))
+
+#endif /* _SYS_SYSCONF_H */
diff --git a/usr/include/sys/sysinfo.h b/usr/include/sys/sysinfo.h
new file mode 100644
index 0000000..8469ba0
--- /dev/null
+++ b/usr/include/sys/sysinfo.h
@@ -0,0 +1,13 @@
+/*
+ * sys/sysinfo.h
+ */
+
+#ifndef _SYS_SYSINFO_H
+#define _SYS_SYSINFO_H
+
+#include <sys/types.h>
+#include <linux/kernel.h>
+
+extern int sysinfo(struct sysinfo *info);
+
+#endif /* _SYS_SYSINFO_H */
diff --git a/usr/include/sys/sysmacros.h b/usr/include/sys/sysmacros.h
new file mode 100644
index 0000000..efb476c
--- /dev/null
+++ b/usr/include/sys/sysmacros.h
@@ -0,0 +1,37 @@
+/*
+ * sys/sysmacros.h
+ *
+ * Constructs to create and pick apart dev_t. The double-underscore
+ * versions are macros so they can be used as constants.
+ */
+
+#ifndef _SYS_SYSMACROS_H
+#define _SYS_SYSMACROS_H
+
+#include <klibc/compiler.h>
+#include <sys/types.h>
+
+#define __major(__d) ((int)(((__d) >> 8) & 0xfffU))
+__static_inline int _major(dev_t __d)
+{
+ return __major(__d);
+}
+#define major(__d) _major(__d)
+
+#define __minor(__d) ((int)(((__d) & 0xffU)|(((__d) >> 12) & 0xfff00U)))
+__static_inline int _minor(dev_t __d)
+{
+ return __minor(__d);
+}
+#define minor(__d) _minor(__d)
+
+#define __makedev(__ma, __mi) \
+ ((dev_t)((((__ma) & 0xfffU) << 8)| \
+ ((__mi) & 0xffU)|(((__mi) & 0xfff00U) << 12)))
+__static_inline dev_t _makedev(int __ma, int __mi)
+{
+ return __makedev(__ma, __mi);
+}
+#define makedev(__ma, __mi) _makedev(__ma, __mi)
+
+#endif /* _SYS_SYSMACROS_H */
diff --git a/usr/include/sys/time.h b/usr/include/sys/time.h
new file mode 100644
index 0000000..423d3d5
--- /dev/null
+++ b/usr/include/sys/time.h
@@ -0,0 +1,117 @@
+/*
+ * sys/time.h
+ */
+
+#ifndef _SYS_TIME_H
+#define _SYS_TIME_H
+
+#include <klibc/extern.h>
+#include <klibc/endian.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+/* struct timespec as used by current kernel UAPI (time64 on 32-bit) */
+struct timespec {
+ __kernel_time64_t tv_sec;
+#if __BYTE_ORDER == __BIG_ENDIAN && __BITS_PER_LONG == 32
+ int :32;
+#endif
+ long tv_nsec;
+#if __BYTE_ORDER == __LITTLE_ENDIAN && __BITS_PER_LONG == 32
+ int :32;
+#endif
+};
+
+/* struct timeval with 64-bit time, not used by kernel UAPI */
+struct timeval {
+ __kernel_time64_t tv_sec;
+ __kernel_suseconds_t tv_usec;
+};
+
+/* struct timeval as used by old kernel UAPI */
+struct timeval_old {
+ __kernel_time_t tv_sec;
+ __kernel_suseconds_t tv_usec;
+};
+
+struct itimerspec {
+ struct timespec it_interval;
+ struct timespec it_value;
+};
+
+struct itimerval {
+ struct timeval_old it_interval;
+ struct timeval_old it_value;
+};
+
+struct timezone {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+#define CLOCK_REALTIME 0
+#define CLOCK_MONOTONIC 1
+#define CLOCK_PROCESS_CPUTIME_ID 2
+#define CLOCK_THREAD_CPUTIME_ID 3
+#define CLOCK_MONOTONIC_RAW 4
+#define CLOCK_REALTIME_COARSE 5
+#define CLOCK_MONOTONIC_COARSE 6
+#define CLOCK_BOOTTIME 7
+#define CLOCK_REALTIME_ALARM 8
+#define CLOCK_BOOTTIME_ALARM 9
+#define CLOCK_TAI 11
+
+#define TIMER_ABSTIME 0x01
+
+/* The 2.6.20 Linux headers always #define FD_ZERO __FD_ZERO, etc, in
+ <linux/time.h> but not all architectures define the
+ double-underscore ones, except __NFDBITS, __FD_SETSIZE and
+ __FDSET_LONGS which are defined in <linux/posix_types.h>.
+
+ Unfortunately, some architectures define the double-underscore ones
+ as inlines, so we can't use a simple #ifdef test. Thus, the only
+ safe option remaining is to #undef the top-level macros. */
+
+#undef FD_ZERO
+#undef FD_SET
+#undef FD_CLR
+#undef FD_ISSET
+#undef FD_SETSIZE
+
+__extern void *memset(void *, int, size_t);
+static inline void FD_ZERO(fd_set *__fdsetp)
+{
+ memset(__fdsetp, 0, sizeof(fd_set));
+}
+static inline void FD_SET(int __fd, fd_set *__fdsetp)
+{
+ __fdsetp->fds_bits[__fd/BITS_PER_LONG] |=
+ (1UL << (__fd % BITS_PER_LONG));
+}
+static inline void FD_CLR(int __fd, fd_set *__fdsetp)
+{
+ __fdsetp->fds_bits[__fd/BITS_PER_LONG] &=
+ ~(1UL << (__fd % BITS_PER_LONG));
+}
+static inline int FD_ISSET(int __fd, fd_set *__fdsetp)
+{
+ return (__fdsetp->fds_bits[__fd/BITS_PER_LONG] >>
+ (__fd % BITS_PER_LONG)) & 1;
+}
+
+#define FD_SETSIZE __FD_SETSIZE
+
+__extern int gettimeofday(struct timeval *, struct timezone *);
+__extern int settimeofday(const struct timeval *, const struct timezone *);
+__extern int clock_gettime(clockid_t, struct timespec *);
+__extern int clock_settime(clockid_t, const struct timespec *);
+__extern int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
+__extern int getitimer(int, struct itimerval *);
+__extern int setitimer(int, const struct itimerval *, struct itimerval *);
+__extern int utimes(const char *, const struct timeval[2]);
+
+#endif /* _SYS_TIME_H */
diff --git a/usr/include/sys/times.h b/usr/include/sys/times.h
new file mode 100644
index 0000000..16be69a
--- /dev/null
+++ b/usr/include/sys/times.h
@@ -0,0 +1,14 @@
+/*
+ * sys/times.h
+ */
+
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/times.h>
+
+__extern clock_t times(struct tms *);
+
+#endif /* _SYS_TIMES_H */
diff --git a/usr/include/sys/types.h b/usr/include/sys/types.h
new file mode 100644
index 0000000..d698ae5
--- /dev/null
+++ b/usr/include/sys/types.h
@@ -0,0 +1,108 @@
+/*
+ * sys/types.h
+ */
+
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define _SSIZE_T
+/* __SIZE_TYPE__ defined either by GCC or <stddef.h> */
+#define unsigned /* nothing, temporarily */
+typedef signed __SIZE_TYPE__ ssize_t;
+#undef unsigned
+
+#include <linux/posix_types.h>
+#include <asm/types.h>
+
+/* Keeps linux/types.h from getting included elsewhere */
+#define _LINUX_TYPES_H
+
+typedef __kernel_fd_set fd_set;
+typedef uint32_t dev_t;
+typedef __kernel_ino_t ino_t;
+typedef __kernel_mode_t mode_t;
+typedef __kernel_loff_t off_t;
+typedef __kernel_loff_t loff_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_daddr_t daddr_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+/* typedef __kernel_timer_t timer_t; */
+typedef int timer_t;
+typedef __kernel_clockid_t clockid_t;
+
+typedef __kernel_uid32_t uid_t;
+typedef __kernel_gid32_t gid_t;
+
+typedef __kernel_fsid_t fsid_t;
+
+/*
+ * The following typedefs are also protected by individual ifdefs for
+ * historical reasons:
+ */
+#ifndef _TIME_T
+#define _TIME_T
+typedef __kernel_time64_t time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef __kernel_clock_t clock_t;
+#endif
+
+#ifndef _CADDR_T
+#define _CADDR_T
+typedef __kernel_caddr_t caddr_t;
+#endif
+
+/* BSD */
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+/* SysV */
+typedef unsigned char unchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+/* More BSD */
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+typedef __u16 __bitwise __sum16;
+typedef __u32 __bitwise __sum32;
+typedef __u64 __bitwise __sum64;
+typedef __u32 __bitwise __wsum;
+
+#define __aligned_u64 __u64 __attribute__((aligned(8)))
+#define __aligned_be64 __be64 __attribute__((aligned(8)))
+#define __aligned_le64 __le64 __attribute__((aligned(8)))
+
+/*
+ * Some headers seem to require this...
+ */
+#ifndef BITS_PER_LONG
+# define BITS_PER_LONG _BITSIZE
+#endif
+
+/*
+ * Some apps want this in <sys/types.h>
+ */
+#include <sys/sysmacros.h>
+
+#endif
diff --git a/usr/include/sys/uio.h b/usr/include/sys/uio.h
new file mode 100644
index 0000000..ee341fb
--- /dev/null
+++ b/usr/include/sys/uio.h
@@ -0,0 +1,15 @@
+/*
+ * sys/uio.h
+ */
+
+#ifndef _SYS_UIO_H
+#define _SYS_UIO_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/uio.h>
+
+__extern int readv(int, const struct iovec *, int);
+__extern int writev(int, const struct iovec *, int);
+
+#endif /* _SYS_UIO_H */
diff --git a/usr/include/sys/un.h b/usr/include/sys/un.h
new file mode 100644
index 0000000..e599f67
--- /dev/null
+++ b/usr/include/sys/un.h
@@ -0,0 +1,11 @@
+/*
+ * <sys/un.h>
+ */
+
+#ifndef _SYS_UN_H
+#define _SYS_UN_H
+
+#include <sys/socket.h>
+#include <linux/un.h>
+
+#endif /* _SYS_UN_H */
diff --git a/usr/include/sys/utime.h b/usr/include/sys/utime.h
new file mode 100644
index 0000000..55415db
--- /dev/null
+++ b/usr/include/sys/utime.h
@@ -0,0 +1,11 @@
+/*
+ * sys/utime.h
+ */
+
+#ifndef _SYS_UTIME_H
+#define _SYS_UTIME_H
+
+#include <sys/types.h>
+#include <linux/utime.h>
+
+#endif /* _SYS_UTIME_H */
diff --git a/usr/include/sys/utsname.h b/usr/include/sys/utsname.h
new file mode 100644
index 0000000..fd55c0b
--- /dev/null
+++ b/usr/include/sys/utsname.h
@@ -0,0 +1,23 @@
+/*
+ * sys/utsname.h
+ */
+
+#ifndef _SYS_UTSNAME_H
+#define _SYS_UTSNAME_H
+
+#include <klibc/extern.h>
+
+#define SYS_NMLN 65
+
+struct utsname {
+ char sysname[SYS_NMLN];
+ char nodename[SYS_NMLN];
+ char release[SYS_NMLN];
+ char version[SYS_NMLN];
+ char machine[SYS_NMLN];
+ char domainname[SYS_NMLN];
+};
+
+__extern int uname(struct utsname *);
+
+#endif /* _SYS_UTSNAME_H */
diff --git a/usr/include/sys/vfs.h b/usr/include/sys/vfs.h
new file mode 100644
index 0000000..6fb1eab
--- /dev/null
+++ b/usr/include/sys/vfs.h
@@ -0,0 +1,132 @@
+/*
+ * sys/vfs.h
+ */
+
+#ifndef _SYS_VFS_H
+#define _SYS_VFS_H
+
+#include <stdint.h>
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <bitsize.h>
+#include <klibc/sysconfig.h>
+
+/* struct statfs64 -- there seems to be two standards -
+ one for 32 and one for 64 bits, and they're incompatible.
+ Worse, some 64-bit platforms seem to use the 32-bit layout.
+ Of course, there is no includable header that does this well. */
+
+#if _KLIBC_STATFS_F_TYPE_64
+
+struct statfs {
+ uint64_t f_type;
+ uint64_t f_bsize;
+ uint64_t f_blocks;
+ uint64_t f_bfree;
+ uint64_t f_bavail;
+ uint64_t f_files;
+ uint64_t f_ffree;
+ __kernel_fsid_t f_fsid;
+ uint64_t f_namelen;
+ uint64_t f_frsize;
+ uint64_t f_spare[5];
+};
+
+#elif _KLIBC_STATFS_F_TYPE_32B
+
+struct statfs {
+ uint32_t f_type;
+ uint32_t f_bsize;
+ uint32_t f_frsize;
+ uint32_t __pad;
+ uint64_t f_blocks;
+ uint64_t f_bfree;
+ uint64_t f_files;
+ uint64_t f_ffree;
+ uint64_t f_bavail;
+ __kernel_fsid_t f_fsid;
+ uint32_t f_namelen;
+ uint32_t f_spare[6];
+};
+
+#else /* not _KLIBC_STATFS_F_TYPE_64 */
+
+struct statfs {
+ uint32_t f_type;
+ uint32_t f_bsize;
+ uint64_t f_blocks;
+ uint64_t f_bfree;
+ uint64_t f_bavail;
+ uint64_t f_files;
+ uint64_t f_ffree;
+ __kernel_fsid_t f_fsid;
+ uint32_t f_namelen;
+ uint32_t f_frsize;
+ uint32_t f_spare[5];
+};
+
+#endif /* _KLIBC_STATFS_F_TYPE_64 */
+
+__extern int statfs(const char *, struct statfs *);
+__extern int fstatfs(int, struct statfs *);
+
+/* Various filesystem types */
+#define ADFS_SUPER_MAGIC 0xadf5
+#define AFFS_SUPER_MAGIC 0xadff
+#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
+#define AUTOFS_SUPER_MAGIC 0x0187
+#define BFS_MAGIC 0x1BADFACE
+#define CAPIFS_SUPER_MAGIC 0x434e
+#define CIFS_MAGIC_NUMBER 0xFF534D42
+#define CODA_SUPER_MAGIC 0x73757245
+#define CRAMFS_MAGIC 0x28cd3d45
+#define DEVFS_SUPER_MAGIC 0x1373
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+#define EFS_SUPER_MAGIC 0x414A53
+#define EVENTPOLLFS_MAGIC 0x03111965
+#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT3_SUPER_MAGIC 0xEF53
+#define GADGETFS_MAGIC 0xaee71ee7
+#define HFSPLUS_SUPER_MAGIC 0x482b
+#define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */
+#define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */
+#define HPFS_SUPER_MAGIC 0xf995e849
+#define HUGETLBFS_MAGIC 0x958458f6
+#define HWGFS_MAGIC 0x12061983
+#define IBMASMFS_MAGIC 0x66726f67
+#define ISOFS_SUPER_MAGIC 0x9660
+#define JFFS2_SUPER_MAGIC 0x72b6
+#define JFFS_MAGIC_BITMASK 0x34383931 /* "1984" */
+#define JFFS_MAGIC_SB_BITMASK 0x07c0 /* 1984 */
+#define JFS_SUPER_MAGIC 0x3153464a /* "JFS1" */
+#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
+#define NCP_SUPER_MAGIC 0x564c
+#define NFS_SUPER_MAGIC 0x6969
+#define NFS_SUPER_MAGIC 0x6969
+#define OPENPROM_SUPER_MAGIC 0x9fa1
+#define OPROFILEFS_MAGIC 0x6f70726f
+#define PFMFS_MAGIC 0xa0b4d889
+#define PIPEFS_MAGIC 0x50495045
+#define PROC_SUPER_MAGIC 0x9fa0
+#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */
+#define RAMFS_MAGIC 0x858458f6
+#define REISERFS_SUPER_MAGIC 0x52654973
+#define ROMFS_MAGIC 0x7275
+#define SMB_SUPER_MAGIC 0x517B
+#define SOCKFS_MAGIC 0x534F434B
+#define SYSFS_MAGIC 0x62656572
+#define TMPFS_MAGIC 0x01021994
+#define UDF_SUPER_MAGIC 0x15013346
+#define UFS_MAGIC 0x00011954
+#define UFS_MAGIC_4GB 0x05231994 /* fs > 4 GB && fs_featurebits */
+#define UFS_MAGIC_FEA 0x00195612 /* fs_featurebits supported */
+#define UFS_MAGIC_LFN 0x00095014 /* fs supports filenames > 14 chars */
+#define UFS_MAGIC_SEC 0x00612195 /* B1 security fs */
+#define USBDEVICE_SUPER_MAGIC 0x9fa2
+#define VXFS_SUPER_MAGIC 0xa501FCF5
+
+#endif /* _SYS_VFS_H */
diff --git a/usr/include/sys/wait.h b/usr/include/sys/wait.h
new file mode 100644
index 0000000..0f5efaf
--- /dev/null
+++ b/usr/include/sys/wait.h
@@ -0,0 +1,28 @@
+/*
+ * sys/wait.h
+ */
+
+#ifndef _SYS_WAIT_H
+#define _SYS_WAIT_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+
+#include <linux/wait.h>
+
+#define WEXITSTATUS(s) (((s) & 0xff00) >> 8)
+#define WTERMSIG(s) ((s) & 0x7f)
+#define WIFEXITED(s) (WTERMSIG(s) == 0)
+#define WIFSTOPPED(s) (WTERMSIG(s) == 0x7f)
+/* Ugly hack to avoid multiple evaluation of "s" */
+#define WIFSIGNALED(s) (WTERMSIG((s)+1) >= 2)
+#define WCOREDUMP(s) ((s) & 0x80)
+#define WSTOPSIG(s) WEXITSTATUS(s)
+
+__extern pid_t wait(int *);
+__extern pid_t waitpid(pid_t, int *, int);
+__extern pid_t wait3(int *, int, struct rusage *);
+__extern pid_t wait4(pid_t, int *, int, struct rusage *);
+
+#endif /* _SYS_WAIT_H */
diff --git a/usr/include/sysexits.h b/usr/include/sysexits.h
new file mode 100644
index 0000000..ef454b9
--- /dev/null
+++ b/usr/include/sysexits.h
@@ -0,0 +1,26 @@
+#ifndef _SYSEXITS_H
+#define _SYSEXITS_H
+
+#define EX_OK 0 /* successful termination */
+
+#define EX__BASE 64 /* base value for error messages */
+
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* configuration error */
+
+#define EX__MAX 78 /* maximum listed value */
+
+#endif /* _SYSEXITS_H */
diff --git a/usr/include/syslog.h b/usr/include/syslog.h
new file mode 100644
index 0000000..71a17e0
--- /dev/null
+++ b/usr/include/syslog.h
@@ -0,0 +1,62 @@
+/*
+ * syslog.h
+ */
+
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+#include <stdio.h>
+#include <klibc/extern.h>
+
+/* Alert levels */
+#define LOG_EMERG 0
+#define LOG_ALERT 1
+#define LOG_CRIT 2
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_NOTICE 5
+#define LOG_INFO 6
+#define LOG_DEBUG 7
+
+#define LOG_PRIMASK 7
+#define LOG_PRI(x) ((x) & LOG_PRIMASK)
+
+/* Facilities; not actually used */
+#define LOG_KERN 0000
+#define LOG_USER 0010
+#define LOG_MAIL 0020
+#define LOG_DAEMON 0030
+#define LOG_AUTH 0040
+#define LOG_SYSLOG 0050
+#define LOG_LPR 0060
+#define LOG_NEWS 0070
+#define LOG_UUCP 0100
+#define LOG_CRON 0110
+#define LOG_AUTHPRIV 0120
+#define LOG_FTP 0130
+#define LOG_LOCAL0 0200
+#define LOG_LOCAL1 0210
+#define LOG_LOCAL2 0220
+#define LOG_LOCAL3 0230
+#define LOG_LOCAL4 0240
+#define LOG_LOCAL5 0250
+#define LOG_LOCAL6 0260
+#define LOG_LOCAL7 0270
+
+#define LOG_FACMASK 01770
+#define LOG_FAC(x) (((x) >> 3) & (LOG_FACMASK >> 3))
+
+/* openlog() flags; only LOG_PID and LOG_PERROR supported */
+#define LOG_PID 0x01 /* include pid with message */
+#define LOG_CONS 0x02 /* write to console on logger error */
+#define LOG_ODELAY 0x04 /* delay connection until syslog() */
+#define LOG_NDELAY 0x08 /* open connection immediately */
+#define LOG_NOWAIT 0x10 /* wait for child processes (unused on linux) */
+#define LOG_PERROR 0x20 /* additional logging to stderr */
+
+__extern void openlog(const char *, int, int);
+__extern void syslog(int, const char *, ...);
+__extern void vsyslog(int, const char *, va_list);
+__extern void closelog(void);
+
+#endif /* _SYSLOG_H */
diff --git a/usr/include/termios.h b/usr/include/termios.h
new file mode 100644
index 0000000..59d9859
--- /dev/null
+++ b/usr/include/termios.h
@@ -0,0 +1,91 @@
+/*
+ * termios.h
+ */
+
+#ifndef _TERMIOS_H
+#define _TERMIOS_H
+
+#include <klibc/extern.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <linux/termios.h>
+
+/* Redefine these so the magic constants == the ioctl number to use. */
+#undef TCSANOW
+#undef TCSADRAIN
+#undef TCSAFLUSH
+#define TCSANOW TCSETS
+#define TCSADRAIN TCSETSW
+#define TCSAFLUSH TCSETSF
+
+static __inline__ int tcgetattr(int __fd, struct termios *__s)
+{
+ return ioctl(__fd, TCGETS, __s);
+}
+
+static __inline__ int tcsetattr(int __fd, int __opt, const struct termios *__s)
+{
+ return ioctl(__fd, __opt, (void *)__s);
+}
+
+static __inline__ int tcflow(int __fd, int __action)
+{
+ return ioctl(__fd, TCXONC, (void *)(intptr_t) __action);
+}
+
+static __inline__ int tcflush(int __fd, int __queue)
+{
+ return ioctl(__fd, TCFLSH, (void *)(intptr_t) __queue);
+}
+
+static __inline__ int tcdrain(int __fd)
+{
+ return ioctl(__fd, TCSBRK, (void *)1L);
+}
+
+static __inline__ pid_t tcgetpgrp(int __fd)
+{
+ pid_t __p;
+ return ioctl(__fd, TIOCGPGRP, &__p) ? (pid_t) - 1 : __p;
+}
+
+static __inline__ pid_t tcgetsid(int __fd)
+{
+ pid_t __p;
+ return ioctl(__fd, TIOCGSID, &__p) ? (pid_t) - 1 : __p;
+}
+
+static __inline__ int tcsendbreak(int __fd, int __duration)
+{
+ return ioctl(__fd, TCSBRKP, (void *)(uintptr_t) __duration);
+}
+
+static __inline__ int tcsetpgrp(int __fd, pid_t __p)
+{
+ return ioctl(__fd, TIOCSPGRP, &__p);
+}
+
+static __inline__ speed_t cfgetospeed(const struct termios *__s)
+{
+ return (speed_t) (__s->c_cflag & CBAUD);
+}
+
+static __inline__ speed_t cfgetispeed(const struct termios *__s)
+{
+ return (speed_t) (__s->c_cflag & CBAUD);
+}
+
+static __inline__ int cfsetospeed(struct termios *__s, speed_t __v)
+{
+ __s->c_cflag = (__s->c_cflag & ~CBAUD) | (__v & CBAUD);
+ return 0;
+}
+
+static __inline__ int cfsetispeed(struct termios *__s, speed_t __v)
+{
+ __s->c_cflag = (__s->c_cflag & ~CBAUD) | (__v & CBAUD);
+ return 0;
+}
+
+#endif /* _TERMIOS_H */
diff --git a/usr/include/time.h b/usr/include/time.h
new file mode 100644
index 0000000..72b2993
--- /dev/null
+++ b/usr/include/time.h
@@ -0,0 +1,18 @@
+/*
+ * time.h
+ */
+
+#ifndef _TIME_H
+#define _TIME_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+
+__extern time_t time(time_t *);
+__extern int nanosleep(const struct timespec *, struct timespec *);
+
+/* klibc-specific but useful since we don't have floating point */
+__extern char *strtotimeval(const char *str, struct timeval *tv);
+__extern char *strtotimespec(const char *str, struct timespec *tv);
+
+#endif /* _TIME_H */
diff --git a/usr/include/unistd.h b/usr/include/unistd.h
new file mode 100644
index 0000000..6f71f7a
--- /dev/null
+++ b/usr/include/unistd.h
@@ -0,0 +1,167 @@
+/*
+ * unistd.h
+ */
+
+#ifndef _UNISTD_H
+#define _UNISTD_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <klibc/seek.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/select.h>
+
+__extern char **environ;
+__extern __noreturn _exit(int);
+
+__extern pid_t fork(void);
+__extern pid_t vfork(void);
+__extern pid_t getpid(void);
+__extern pid_t getpgid(pid_t);
+__extern int setpgid(pid_t, pid_t);
+__extern pid_t getppid(void);
+__extern pid_t getpgrp(void);
+__extern int setpgrp(void);
+__extern pid_t setsid(void);
+__extern pid_t getsid(pid_t);
+__extern int execv(const char *, char *const *);
+__extern int execvp(const char *, char *const *);
+__extern int execve(const char *, char *const *, char *const *);
+__extern int execvpe(const char *, char *const *, char *const *);
+__extern int execl(const char *, const char *, ...);
+__extern int execlp(const char *, const char *, ...);
+__extern int execle(const char *, const char *, ...);
+__extern int execlpe(const char *, const char *, ...);
+
+__extern int nice(int);
+__extern int setuid(uid_t);
+__extern uid_t getuid(void);
+__extern int seteuid(uid_t);
+__extern uid_t geteuid(void);
+__extern int setgid(gid_t);
+__extern gid_t getgid(void);
+__extern int setegid(gid_t);
+__extern gid_t getegid(void);
+__extern int getgroups(int, gid_t *);
+__extern int setgroups(size_t, const gid_t *);
+__extern int setreuid(uid_t, uid_t);
+__extern int setregid(gid_t, gid_t);
+__extern int setresuid(uid_t, uid_t, uid_t);
+__extern int setresgid(gid_t, gid_t, gid_t);
+__extern int getfsuid(uid_t);
+__extern int setfsuid(uid_t);
+
+/* Macros for access() */
+#define R_OK 4 /* Read */
+#define W_OK 2 /* Write */
+#define X_OK 1 /* Execute */
+#define F_OK 0 /* Existence */
+
+__extern int access(const char *, int);
+__extern int faccessat(int, const char *, int, int);
+__extern int link(const char *, const char *);
+__extern int linkat(int, const char *, int, const char *, int);
+__extern int unlink(const char *);
+__extern int unlinkat(int, const char *, int);
+__extern int chdir(const char *);
+__extern int fchdir(int);
+__extern int chmod(const char *, mode_t);
+__extern int fchmod(int, mode_t);
+__extern int mkdir(const char *, mode_t);
+__extern int mkdirat(int, const char *, mode_t);
+__extern int rmdir(const char *);
+__extern int pipe(int[2]);
+__extern int pipe2(int[2], int);
+__extern int chroot(const char *);
+__extern int symlink(const char *, const char *);
+__extern int symlinkat(const char *, int, const char *);
+__extern int readlink(const char *, char *, size_t);
+__extern int readlinkat(int, const char *, char *, size_t);
+__extern int chown(const char *, uid_t, gid_t);
+__extern int fchown(int, uid_t, gid_t);
+__extern int lchown(const char *, uid_t, gid_t);
+__extern char *getcwd(char *, size_t);
+__extern int fchownat(int, const char *, uid_t, gid_t, int);
+
+/* Also in <fcntl.h> */
+#ifndef _KLIBC_IN_OPEN_C
+__extern int open(const char *, int, ...);
+__extern int openat(int, const char *, int, ...);
+#endif
+__extern int creat(const char *, mode_t);
+__extern int close(int);
+__extern off_t lseek(int, off_t, int);
+/* off_t is 64 bits now even on 32-bit platforms; see llseek.c */
+static __inline__ off_t llseek(int __f, off_t __o, int __w)
+{
+ return lseek(__f, __o, __w);
+}
+
+__extern ssize_t read(int, void *, size_t);
+__extern ssize_t write(int, const void *, size_t);
+__extern ssize_t pread(int, void *, size_t, off_t);
+__extern ssize_t pwrite(int, const void *, size_t, off_t);
+
+__extern int dup(int);
+__extern int dup2(int, int);
+__extern int dup3(int, int, int);
+__extern int fcntl(int, int, ...);
+__extern int ioctl(int, int, void *);
+__extern int ftruncate(int, off_t);
+
+/*
+ * Macros for sync_file_range()
+ */
+#define SYNC_FILE_RANGE_WAIT_BEFORE 1
+#define SYNC_FILE_RANGE_WRITE 2
+#define SYNC_FILE_RANGE_WAIT_AFTER 4
+
+__extern int sync(void);
+__extern int fsync(int);
+__extern int fdatasync(int);
+__extern int sync_file_range(int, off_t, off_t, unsigned int);
+
+__extern int pause(void);
+__extern unsigned int alarm(unsigned int);
+__extern unsigned int sleep(unsigned int);
+__extern void usleep(unsigned long);
+
+__extern int gethostname(char *, size_t);
+__extern int sethostname(const char *, size_t);
+__extern int getdomainname(char *, size_t);
+__extern int setdomainname(const char *, size_t);
+
+__extern void *__brk(void *);
+__extern int brk(void *);
+__extern void *sbrk(ptrdiff_t);
+
+__extern int getopt(int, char *const *, const char *);
+__extern char *optarg;
+__extern int optind, opterr, optopt;
+
+__extern int isatty(int);
+
+__extern unsigned int __page_size;
+__must_inline int getpagesize(void)
+{
+ return __page_size;
+}
+
+__extern unsigned int __page_shift;
+__must_inline int __getpageshift(void)
+{
+ return __page_shift;
+}
+
+__extern int daemon(int, int);
+
+/* Standard file descriptor numbers. */
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+/* This #include must be at the end */
+#include <sys/sysconf.h>
+
+#endif /* _UNISTD_H */
diff --git a/usr/include/utime.h b/usr/include/utime.h
new file mode 100644
index 0000000..fa00604
--- /dev/null
+++ b/usr/include/utime.h
@@ -0,0 +1,14 @@
+/*
+ * utime.h
+ */
+
+#ifndef _UTIME_H
+#define _UTIME_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <linux/utime.h>
+
+__extern int utime(const char *, const struct utimbuf *);
+
+#endif /* _UTIME_H */
diff --git a/usr/include/zconf.h b/usr/include/zconf.h
new file mode 100644
index 0000000..afe324f
--- /dev/null
+++ b/usr/include/zconf.h
@@ -0,0 +1,332 @@
+/* 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
+ */
+
+/* @(#) $Id: zconf.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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
+#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/usr/include/zlib.h b/usr/include/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/usr/include/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/usr/kinit/.gitignore b/usr/kinit/.gitignore
new file mode 100644
index 0000000..f5a4f24
--- /dev/null
+++ b/usr/kinit/.gitignore
@@ -0,0 +1,3 @@
+lib.a
+kinit
+kinit.shared
diff --git a/usr/kinit/Kbuild b/usr/kinit/Kbuild
new file mode 100644
index 0000000..6cd5ba6
--- /dev/null
+++ b/usr/kinit/Kbuild
@@ -0,0 +1,43 @@
+#
+# Kbuild file for kinit
+#
+
+# library part of kinit. Is used by programs in sub-directories (resume et al)
+lib-y := name_to_dev.o devname.o getarg.o capabilities.o
+# use lib for kinit
+static/kinit-y := lib.a
+
+static/kinit-y += kinit.o do_mounts.o ramdisk_load.o initrd.o
+static/kinit-y += getintfile.o readfile.o xpio.o
+static/kinit-y += do_mounts_md.o do_mounts_mtd.o nfsroot.o
+
+static/kinit-y += ipconfig/
+static/kinit-y += nfsmount/
+static/kinit-y += run-init/
+static/kinit-y += fstype/
+static/kinit-y += resume/
+
+static-y := static/kinit
+shared-y := shared/kinit
+shared/kinit-y := $(static/kinit-y)
+
+# Additional include paths files
+KLIBCCFLAGS += -I$(srctree)/$(src)/fstype \
+ -I$(srctree)/$(src)/ipconfig \
+ -I$(srctree)/$(src)/nfsmount \
+ -I$(srctree)/$(src)/resume \
+ -I$(srctree)/$(src)/run-init
+
+# Cleaning
+targets += static/kinit static/kinit.g shared/kinit shared/kinit.g
+subdir- := fstype ipconfig nfsmount resume run-init
+
+# Clean deletes the static and shared dir
+clean-dirs := static shared
+
+# install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := shared/kinit
+else
+install-y := static/kinit
+endif
diff --git a/usr/kinit/README b/usr/kinit/README
new file mode 100644
index 0000000..fa7f645
--- /dev/null
+++ b/usr/kinit/README
@@ -0,0 +1,9 @@
+kinit - tiny init program
+-------------------------
+
+This program is intended for use as /sbin/init in an initramfs
+environment. It currently replaces the kernel's ipconfig and nfsroot
+code.
+
+--
+Bryan O'Sullivan (2003/05/05)
diff --git a/usr/kinit/capabilities.c b/usr/kinit/capabilities.c
new file mode 100644
index 0000000..2c61025
--- /dev/null
+++ b/usr/kinit/capabilities.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved
+ * Author: mikew@google.com (Mike Waychison)
+ */
+
+/*
+ * We have to include the klibc types.h here to keep the kernel's
+ * types.h from being used.
+ */
+#include <sys/types.h>
+
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/utsname.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "kinit.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define MAKE_CAP(cap) [cap] = { .cap_name = #cap }
+
+struct capability {
+ const char *cap_name;
+} capabilities[] = {
+ MAKE_CAP(CAP_CHOWN),
+ MAKE_CAP(CAP_DAC_OVERRIDE),
+ MAKE_CAP(CAP_DAC_READ_SEARCH),
+ MAKE_CAP(CAP_FOWNER),
+ MAKE_CAP(CAP_FSETID),
+ MAKE_CAP(CAP_KILL),
+ MAKE_CAP(CAP_SETGID),
+ MAKE_CAP(CAP_SETUID),
+ MAKE_CAP(CAP_SETPCAP),
+ MAKE_CAP(CAP_LINUX_IMMUTABLE),
+ MAKE_CAP(CAP_NET_BIND_SERVICE),
+ MAKE_CAP(CAP_NET_BROADCAST),
+ MAKE_CAP(CAP_NET_ADMIN),
+ MAKE_CAP(CAP_NET_RAW),
+ MAKE_CAP(CAP_IPC_LOCK),
+ MAKE_CAP(CAP_IPC_OWNER),
+ MAKE_CAP(CAP_SYS_MODULE),
+ MAKE_CAP(CAP_SYS_RAWIO),
+ MAKE_CAP(CAP_SYS_CHROOT),
+ MAKE_CAP(CAP_SYS_PTRACE),
+ MAKE_CAP(CAP_SYS_PACCT),
+ MAKE_CAP(CAP_SYS_ADMIN),
+ MAKE_CAP(CAP_SYS_BOOT),
+ MAKE_CAP(CAP_SYS_NICE),
+ MAKE_CAP(CAP_SYS_RESOURCE),
+ MAKE_CAP(CAP_SYS_TIME),
+ MAKE_CAP(CAP_SYS_TTY_CONFIG),
+ MAKE_CAP(CAP_MKNOD),
+ MAKE_CAP(CAP_LEASE),
+ MAKE_CAP(CAP_AUDIT_WRITE),
+ MAKE_CAP(CAP_AUDIT_CONTROL),
+ MAKE_CAP(CAP_SETFCAP),
+ MAKE_CAP(CAP_MAC_OVERRIDE),
+ MAKE_CAP(CAP_MAC_ADMIN),
+ MAKE_CAP(CAP_SYSLOG),
+};
+
+static void fail(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+static void fail(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ exit(1);
+}
+
+/*
+ * Find the capability ordinal by name, and return its ordinal.
+ * Returns -1 on failure.
+ */
+static int find_capability(const char *s)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(capabilities); i++) {
+ if (capabilities[i].cap_name
+ && strcasecmp(s, capabilities[i].cap_name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void do_capset(int cap_ordinal)
+{
+ struct __user_cap_header_struct hdr;
+ struct __user_cap_data_struct caps[2];
+
+ /* Get the current capability mask */
+ hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ hdr.pid = getpid();
+ if (capget(&hdr, caps)) {
+ perror("capget()");
+ exit(1);
+ }
+
+ /* Drop the bits */
+ if (cap_ordinal < 32)
+ caps[0].inheritable &= ~(1U << cap_ordinal);
+ else
+ caps[1].inheritable &= ~(1U << (cap_ordinal - 32));
+
+ /* And drop the capability. */
+ hdr.version = _LINUX_CAPABILITY_VERSION_3;
+ hdr.pid = getpid();
+ if (capset(&hdr, caps))
+ fail("Couldn't drop the capability \"%s\"\n",
+ capabilities[cap_ordinal].cap_name);
+}
+
+static void do_bset(int cap_ordinal)
+{
+ int ret;
+
+ ret = prctl(PR_CAPBSET_READ, cap_ordinal);
+ if (ret == 1) {
+ ret = prctl(PR_CAPBSET_DROP, cap_ordinal);
+ if (ret != 0)
+ fail("Error dropping capability %s from bset\n",
+ capabilities[cap_ordinal].cap_name);
+ } else if (ret < 0)
+ fail("Kernel doesn't recognize capability %d\n", cap_ordinal);
+}
+
+static void do_usermodehelper_file(const char *filename, int cap_ordinal)
+{
+ uint32_t lo32, hi32;
+ FILE *file;
+ static const size_t buf_size = 80;
+ char buf[buf_size];
+ char tail;
+ size_t bytes_read;
+ int ret;
+
+ /* Try and open the file */
+ file = fopen(filename, "r+");
+ if (!file && errno == ENOENT)
+ fail("Could not disable usermode helpers capabilities as "
+ "%s is not available\n", filename);
+ if (!file)
+ fail("Failed to access file %s errno %d\n", filename, errno);
+
+ /* Read and process the current bits */
+ bytes_read = fread(buf, 1, buf_size - 1, file);
+ if (bytes_read == 0)
+ fail("Trouble reading %s\n", filename);
+ buf[bytes_read] = '\0';
+ ret = sscanf(buf, "%u %u %c", &lo32, &hi32, &tail);
+ if (ret != 2)
+ fail("Failed to understand %s \"%s\"\n", filename, buf);
+
+ /* Clear the bits in the local copy */
+ if (cap_ordinal < 32)
+ lo32 &= ~(1 << cap_ordinal);
+ else
+ hi32 &= ~(1 << (cap_ordinal - 32));
+
+ /* Commit the new bit masks to the kernel */
+ ret = fflush(file);
+ if (ret != 0)
+ fail("Failed on file %s to fflush %d\n", filename, ret);
+ sprintf(buf, "%u %u", lo32, hi32);
+ ret = fwrite(buf, 1, strlen(buf) + 1, file);
+ if (ret != 0)
+ fail("Failed to commit usermode helper bitmasks: %d\n", ret);
+
+ /* Cleanup */
+ fclose(file);
+}
+
+static void do_usermodehelper(int cap_ordinal)
+{
+ static const char * const files[] = {
+ "/proc/sys/kernel/usermodehelper/bset",
+ "/proc/sys/kernel/usermodehelper/inheritable",
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(files); i++)
+ do_usermodehelper_file(files[i], cap_ordinal);
+}
+
+static void drop_capability(int cap_ordinal)
+{
+ do_usermodehelper(cap_ordinal);
+ do_bset(cap_ordinal);
+ do_capset(cap_ordinal);
+
+ printf("Dropped capability: %s\n", capabilities[cap_ordinal].cap_name);
+}
+
+int drop_capabilities(const char *caps)
+{
+ char *s, *saveptr = NULL;
+ char *token;
+
+ if (!caps)
+ return 0;
+
+ /* Create a duplicate string that can be modified. */
+ s = strdup(caps);
+ if (!s)
+ fail("Failed to drop caps as requested. Exiting\n");
+
+ token = strtok_r(s, ",", &saveptr);
+ while (token) {
+ int cap_ordinal = find_capability(token);
+
+ if (cap_ordinal < 0)
+ fail("Could not understand capability name \"%s\" "
+ "on command line, failing init\n", token);
+
+ drop_capability(cap_ordinal);
+
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+
+ free(s);
+ return 0;
+}
diff --git a/usr/kinit/capabilities.h b/usr/kinit/capabilities.h
new file mode 100644
index 0000000..a32a66a
--- /dev/null
+++ b/usr/kinit/capabilities.h
@@ -0,0 +1,10 @@
+/*
+ * capabilities.h
+ */
+
+#ifndef KINIT_CAPABILITIES_H
+#define KINIT_CAPABILITIES_H
+
+int drop_capabilities(const char *caps);
+
+#endif /* KINIT_CAPABILITIES_H */
diff --git a/usr/kinit/devname.c b/usr/kinit/devname.c
new file mode 100644
index 0000000..c327e3b
--- /dev/null
+++ b/usr/kinit/devname.c
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+#include "kinit.h"
+
+/*
+ * Print the name of a block device.
+ */
+#define BUF_SIZE 512
+
+static int scansysdir(char *namebuf, char *sysdir, dev_t dev)
+{
+ char *dirtailptr = strchr(sysdir, '\0');
+ DIR *dir;
+ int done = 0;
+ struct dirent *de;
+ char *systail;
+ FILE *sysdev;
+ unsigned long ma, mi;
+ char *ep;
+ ssize_t rd;
+
+ dir = opendir(sysdir);
+ if (!dir)
+ return 0;
+
+ *dirtailptr++ = '/';
+
+ while (!done && (de = readdir(dir))) {
+ /* Assume if we see a dot-name in sysfs it's special */
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (de->d_type != DT_UNKNOWN && de->d_type != DT_DIR)
+ continue;
+
+ if (strlen(de->d_name) >=
+ (BUF_SIZE - 64) - (dirtailptr - sysdir))
+ continue; /* Badness... */
+
+ strcpy(dirtailptr, de->d_name);
+ systail = strchr(sysdir, '\0');
+
+ strcpy(systail, "/dev");
+ sysdev = fopen(sysdir, "r");
+ if (!sysdev)
+ continue;
+
+ /* Abusing the namebuf as temporary storage here. */
+ rd = fread(namebuf, 1, BUF_SIZE, sysdev);
+ namebuf[rd] = '\0'; /* Just in case... */
+
+ fclose(sysdev);
+
+ ma = strtoul(namebuf, &ep, 10);
+ if (ma != major(dev) || *ep != ':')
+ continue;
+
+ mi = strtoul(ep + 1, &ep, 10);
+ if (*ep != '\n')
+ continue;
+
+ if (mi == minor(dev)) {
+ /* Found it! */
+ strcpy(namebuf, de->d_name);
+ done = 1;
+ } else {
+ /* we have a major number match, scan for partitions */
+ *systail = '\0';
+ done = scansysdir(namebuf, sysdir, dev);
+ }
+ }
+
+ closedir(dir);
+ return done;
+}
+
+const char *bdevname(dev_t dev)
+{
+ static char buf[BUF_SIZE];
+ char sysdir[BUF_SIZE];
+ char *p;
+
+ strcpy(sysdir, "/sys/block");
+
+ if (!scansysdir(buf, sysdir, dev))
+ strcpy(buf, "dev"); /* prints e.g. dev(3,5) */
+
+ p = strchr(buf, '\0');
+ snprintf(p, sizeof buf - (p - buf), "(%d,%d)", major(dev), minor(dev));
+
+ return buf;
+}
+
+#ifdef TEST_DEVNAME /* Standalone test */
+
+int main(int argc, char *argv[])
+{
+ dev_t dev;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ dev = strtoul(argv[i], NULL, 0);
+
+ printf("0x%08x = %s\n", (unsigned int)dev, bdevname(dev));
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/usr/kinit/do_mounts.c b/usr/kinit/do_mounts.c
new file mode 100644
index 0000000..b648299
--- /dev/null
+++ b/usr/kinit/do_mounts.c
@@ -0,0 +1,533 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <mntent.h>
+
+#include "do_mounts.h"
+#include "kinit.h"
+#include "fstype.h"
+#include "zlib.h"
+
+#ifndef MS_RELATIME
+# define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */
+#endif
+
+#ifndef MS_STRICTATIME
+# define MS_STRICTATIME (1<<24) /* Always perform atime updates */
+#endif
+
+/*
+ * The following mount option parsing was stolen from
+ *
+ * usr/utils/mount_opts.c
+ *
+ * and adapted to add some later mount flags.
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+struct mount_opts {
+ const char str[16];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+
+/* These must be in alphabetic order! */
+static const struct mount_opts options[] = {
+ /* name mask set noset */
+ {"async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS},
+ {"atime", MS_NOATIME, 0, MS_NOATIME},
+ {"bind", MS_TYPE, MS_BIND, 0,},
+ {"dev", MS_NODEV, 0, MS_NODEV},
+ {"diratime", MS_NODIRATIME, 0, MS_NODIRATIME},
+ {"dirsync", MS_DIRSYNC, MS_DIRSYNC, 0},
+ {"exec", MS_NOEXEC, 0, MS_NOEXEC},
+ {"move", MS_TYPE, MS_MOVE, 0},
+ {"nodev", MS_NODEV, MS_NODEV, 0},
+ {"noexec", MS_NOEXEC, MS_NOEXEC, 0},
+ {"nosuid", MS_NOSUID, MS_NOSUID, 0},
+ {"recurse", MS_REC, MS_REC, 0},
+ {"relatime", MS_RELATIME, MS_RELATIME, 0},
+ {"remount", MS_TYPE, MS_REMOUNT, 0},
+ {"ro", MS_RDONLY, MS_RDONLY, 0},
+ {"rw", MS_RDONLY, 0, MS_RDONLY},
+ {"strictatime", MS_STRICTATIME, MS_STRICTATIME, 0},
+ {"suid", MS_NOSUID, 0, MS_NOSUID},
+ {"sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0},
+ {"verbose", MS_VERBOSE, MS_VERBOSE, 0},
+};
+
+/*
+ * Append 's' to 'extra->str'. 's' is a mount option that can't be turned into
+ * a flag. Return 0 on success, -1 on error.
+ */
+static int add_extra_option(struct extra_opts *extra, char *s)
+{
+ int len = strlen(s);
+ int newlen = extra->used_size + len;
+
+ if (extra->str)
+ len++; /* +1 for ',' */
+
+ if (newlen >= extra->alloc_size) {
+ char *new;
+
+ new = realloc(extra->str, newlen + 1); /* +1 for NUL */
+ if (!new) {
+ if (extra->str)
+ free(extra->str);
+ return -1;
+ }
+
+ extra->str = new;
+ extra->end = extra->str + extra->used_size;
+ extra->alloc_size = newlen;
+ }
+
+ if (extra->used_size) {
+ *extra->end = ',';
+ extra->end++;
+ }
+ strcpy(extra->end, s);
+ extra->used_size += len;
+
+ return 0;
+}
+
+/*
+ * Parse the options in 'arg'; put numeric mount flags into 'flags' and
+ * the rest into 'extra'. Return 0 on success, -1 on error.
+ */
+static int
+parse_mount_options(char *arg, unsigned long *flags, struct extra_opts *extra)
+{
+ char *s;
+
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res;
+ int no = (s[0] == 'n' && s[1] == 'o');
+ int found = 0;
+
+ if (no)
+ s += 2;
+
+ for (i = 0; i < ARRAY_SIZE(options); i++) {
+
+ res = strcmp(s, options[i].str);
+ if (res == 0) {
+ found = 1;
+ *flags &= ~options[i].rwmask;
+ if (no)
+ *flags |= options[i].rwnoset;
+ else
+ *flags |= options[i].rwset;
+ break;
+
+ /* If we're beyond 's' alphabetically, we're done */
+ } else if (res < 0)
+ break;
+ }
+ if (! found)
+ if (add_extra_option(extra, opt) != 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Create the device node "name" */
+int create_dev(const char *name, dev_t dev)
+{
+ unlink(name);
+ return mknod(name, S_IFBLK | 0600, dev);
+}
+
+
+/*
+ * If there is not a block device for the input 'name', try to create one; if
+ * we can't that's okay.
+ */
+static void create_dev_if_not_present(const char *name)
+{
+ struct stat st;
+ dev_t dev;
+
+ if (stat(name, &st) == 0) /* file present; we're done */
+ return;
+ dev = name_to_dev_t(name);
+ if (dev)
+ (void) create_dev(name, dev);
+}
+
+
+/* mount a filesystem, possibly trying a set of different types */
+const char *mount_block(const char *source, const char *target,
+ const char *type, unsigned long flags,
+ const void *data)
+{
+ char *fslist, *p, *ep;
+ const char *rp;
+ ssize_t fsbytes;
+ int fd;
+
+ if (type) {
+ dprintf("kinit: trying to mount %s on %s "
+ "with type %s, flags 0x%lx, data '%s'\n",
+ source, target, type, flags, (char *)data);
+ int rv = mount(source, target, type, flags, data);
+
+ if (rv != 0)
+ dprintf("kinit: mount %s on %s failed "
+ "with errno = %d\n",
+ source, target, errno);
+ /* Mount readonly if necessary */
+ if (rv == -1 && errno == EACCES && !(flags & MS_RDONLY))
+ rv = mount(source, target, type, flags | MS_RDONLY,
+ data);
+ return rv ? NULL : type;
+ }
+
+ /* If no type given, try to identify the type first; this
+ also takes care of specific ordering requirements, like
+ ext3 before ext2... */
+ fd = open(source, O_RDONLY);
+ if (fd >= 0) {
+ int err = identify_fs(fd, &type, NULL, 0);
+ close(fd);
+
+ if (!err && type) {
+ dprintf("kinit: %s appears to be a %s filesystem\n",
+ source, type);
+ type = mount_block(source, target, type, flags, data);
+ if (type)
+ return type;
+ }
+ }
+
+ dprintf("kinit: failed to identify filesystem %s, trying all\n",
+ source);
+
+ fsbytes = readfile("/proc/filesystems", &fslist);
+
+ errno = EINVAL;
+ if (fsbytes < 0)
+ return NULL;
+
+ p = fslist;
+ ep = fslist + fsbytes;
+
+ rp = NULL;
+
+ while (p < ep) {
+ type = p;
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+ *p++ = '\0';
+ /* We can't mount a block device as a "nodev" fs */
+ if (*type != '\t')
+ continue;
+
+ type++;
+ rp = mount_block(source, target, type, flags, data);
+ if (rp)
+ break;
+ if (errno != EINVAL)
+ break;
+ }
+
+ free(fslist);
+ return rp;
+}
+
+/* mount the root filesystem from a block device */
+static int
+mount_block_root(int argc, char *argv[], dev_t root_dev,
+ const char *type, unsigned long flags)
+{
+ const char *data, *rp;
+
+ data = get_arg(argc, argv, "rootflags=");
+ create_dev("/dev/root", root_dev);
+
+ errno = 0;
+
+ if (type) {
+ if ((rp = mount_block("/dev/root", "/root", type, flags, data)))
+ goto ok;
+ if (errno != EINVAL)
+ goto bad;
+ }
+
+ if (!errno
+ && (rp = mount_block("/dev/root", "/root", NULL, flags, data)))
+ goto ok;
+
+bad:
+ if (errno != EINVAL) {
+ /*
+ * Allow the user to distinguish between failed open
+ * and bad superblock on root device.
+ */
+ fprintf(stderr, "%s: Cannot open root device %s\n",
+ progname, bdevname(root_dev));
+ return -errno;
+ } else {
+ fprintf(stderr, "%s: Unable to mount root fs on device %s\n",
+ progname, bdevname(root_dev));
+ return -ESRCH;
+ }
+
+ok:
+ printf("%s: Mounted root (%s filesystem)%s.\n",
+ progname, rp, (flags & MS_RDONLY) ? " readonly" : "");
+ return 0;
+}
+
+static int
+mount_roots(int argc, char *argv[], const char *root_dev_name)
+{
+ char *roots = strdup(root_dev_name);
+ char *root;
+ const char *sep = ",";
+ char *saveptr;
+ int ret = -ESRCH;
+
+ root = strtok_r(roots, sep, &saveptr);
+ while (root) {
+ dev_t root_dev;
+
+ dprintf("kinit: trying to mount %s\n", root);
+ root_dev = name_to_dev_t(root);
+ ret = mount_root(argc, argv, root_dev, root);
+ if (!ret)
+ break;
+ root = strtok_r(NULL, sep, &saveptr);
+ }
+ free(roots);
+ return ret;
+}
+
+int
+mount_root(int argc, char *argv[], dev_t root_dev, const char *root_dev_name)
+{
+ unsigned long flags = MS_RDONLY | MS_VERBOSE;
+ int ret;
+ const char *type = get_arg(argc, argv, "rootfstype=");
+
+ if (get_flag(argc, argv, "rw") > get_flag(argc, argv, "ro")) {
+ dprintf("kinit: mounting root rw\n");
+ flags &= ~MS_RDONLY;
+ }
+
+ if (type) {
+ if (!strcmp(type, "nfs"))
+ root_dev = Root_NFS;
+ else if (!strcmp(type, "jffs2") && !major(root_dev))
+ root_dev = Root_MTD;
+ }
+
+ switch (root_dev) {
+ case Root_NFS:
+ ret = mount_nfs_root(argc, argv, flags);
+ break;
+ case Root_MTD:
+ ret = mount_mtd_root(argc, argv, root_dev_name, type, flags);
+ break;
+ default:
+ ret = mount_block_root(argc, argv, root_dev, type, flags);
+ break;
+ }
+
+ if (!ret)
+ chdir("/root");
+
+ return ret;
+}
+
+/* Allocate a buffer and prepend '/root' onto 'src'. */
+static char *prepend_root_dir(const char *src)
+{
+ size_t len = strlen(src) + 6; /* "/root" */
+ char *p = malloc(len);
+
+ if (!p)
+ return NULL;
+
+ strcpy(p, "/root");
+ strcat(p, src);
+ return p;
+}
+
+int do_cmdline_mounts(int argc, char *argv[])
+{
+ int arg_i;
+ int ret = 0;
+
+ for (arg_i = 0; arg_i < argc; arg_i++) {
+ const char *fs_dev, *fs_dir, *fs_type;
+ char *fs_opts;
+ unsigned long flags = 0;
+ char *saveptr = NULL;
+ char *new_dir;
+ struct extra_opts extra = { 0, 0, 0, 0 };
+
+ if (strncmp(argv[arg_i], "kinit_mount=", 12))
+ continue;
+ /*
+ * Format:
+ * <fs_dev>;<dir>;<fs_type>;[opt1],[optn...]
+ */
+ fs_dev = strtok_r(&argv[arg_i][12], ";", &saveptr);
+ if (!fs_dev) {
+ fprintf(stderr, "Failed to parse fs_dev\n");
+ continue;
+ }
+ fs_dir = strtok_r(NULL, ";", &saveptr);
+ if (!fs_dir) {
+ fprintf(stderr, "Failed to parse fs_dir\n");
+ continue;
+ }
+ fs_type = strtok_r(NULL, ";", &saveptr);
+ if (!fs_type) {
+ fprintf(stderr, "Failed to parse fs_type\n");
+ continue;
+ }
+ fs_opts = strtok_r(NULL, ";", &saveptr);
+ /* Don't error if there is no option string sent */
+
+ new_dir = prepend_root_dir(fs_dir);
+ if (! new_dir)
+ return -ENOMEM;
+ create_dev_if_not_present(fs_dev);
+ ret = parse_mount_options(fs_opts, &flags, &extra);
+ if (ret != 0)
+ break;
+
+ if (!mount_block(fs_dev, new_dir, fs_type,
+ flags, extra.str))
+ fprintf(stderr, "Skipping failed mount '%s'\n", fs_dev);
+ free(new_dir);
+ if (extra.str)
+ free(extra.str);
+ }
+ return ret;
+}
+
+int do_fstab_mounts(FILE *fp)
+{
+ struct mntent *ent = NULL;
+ char *new_dir;
+ int ret = 0;
+
+ while ((ent = getmntent(fp))) {
+ unsigned long flags = 0;
+ struct extra_opts extra = { 0, 0, 0, 0 };
+
+ new_dir = prepend_root_dir(ent->mnt_dir);
+ if (! new_dir)
+ return -ENOMEM;
+ create_dev_if_not_present(ent->mnt_fsname);
+ ret = parse_mount_options(ent->mnt_opts, &flags, &extra);
+ if (ret != 0)
+ break;
+
+ if (!mount_block(ent->mnt_fsname,
+ new_dir,
+ ent->mnt_type,
+ flags,
+ extra.str)) {
+ fprintf(stderr, "Skipping failed mount '%s'\n",
+ ent->mnt_fsname);
+ }
+ free(new_dir);
+ if (extra.str)
+ free(extra.str);
+ }
+ return 0;
+}
+
+int do_mounts(int argc, char *argv[])
+{
+ const char *root_dev_name = get_arg(argc, argv, "root=");
+ const char *root_delay = get_arg(argc, argv, "rootdelay=");
+ const char *load_ramdisk = get_arg(argc, argv, "load_ramdisk=");
+ dev_t root_dev = 0;
+ int err;
+ FILE *fp;
+
+ dprintf("kinit: do_mounts\n");
+
+ if (root_delay) {
+ int delay = atoi(root_delay);
+ fprintf(stderr, "Waiting %d s before mounting root device...\n",
+ delay);
+ sleep(delay);
+ }
+
+ md_run(argc, argv);
+
+ if (root_dev_name) {
+ root_dev = name_to_dev_t(root_dev_name);
+ } else if (get_arg(argc, argv, "nfsroot=") ||
+ get_arg(argc, argv, "nfsaddrs=")) {
+ root_dev = Root_NFS;
+ } else {
+ long rootdev;
+ getintfile("/proc/sys/kernel/real-root-dev", &rootdev);
+ root_dev = (dev_t) rootdev;
+ }
+
+ dprintf("kinit: root_dev = %s\n", bdevname(root_dev));
+
+ if (initrd_load(argc, argv, root_dev)) {
+ dprintf("initrd loaded\n");
+ return 0;
+ }
+
+ if (load_ramdisk && atoi(load_ramdisk)) {
+ if (ramdisk_load(argc, argv))
+ root_dev = Root_RAM0;
+ }
+
+ if (root_dev == Root_MULTI)
+ err = mount_roots(argc, argv, root_dev_name);
+ else
+ err = mount_root(argc, argv, root_dev, root_dev_name);
+
+ if (err)
+ return err;
+
+ if ((fp = setmntent("/etc/fstab", "r"))) {
+ err = do_fstab_mounts(fp);
+ fclose(fp);
+ }
+
+ if (err)
+ return err;
+
+ if (get_arg(argc, argv, "kinit_mount="))
+ err = do_cmdline_mounts(argc, argv);
+ return err;
+}
diff --git a/usr/kinit/do_mounts.h b/usr/kinit/do_mounts.h
new file mode 100644
index 0000000..99bc6a6
--- /dev/null
+++ b/usr/kinit/do_mounts.h
@@ -0,0 +1,49 @@
+/*
+ * do_mounts.h
+ */
+
+#ifndef DO_MOUNTS_H
+#define DO_MOUNTS_H
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/stat.h>
+
+#define Root_RAM0 __makedev(1, 0)
+
+/* These device numbers are only used internally */
+#define Root_NFS __makedev(0, 255)
+#define Root_MTD __makedev(0, 254)
+#define Root_MULTI __makedev(0, 253)
+
+int create_dev(const char *name, dev_t dev);
+
+dev_t name_to_dev_t(const char *name);
+
+const char *mount_block(const char *source, const char *target,
+ const char *type, unsigned long flags,
+ const void *data);
+
+int mount_root(int argc, char *argv[], dev_t root_dev,
+ const char *root_dev_name);
+
+int mount_mtd_root(int argc, char *argv[], const char *root_dev_name,
+ const char *type, unsigned long flags);
+
+int do_mounts(int argc, char *argv[]);
+
+int initrd_load(int argc, char *argv[], dev_t root_dev);
+
+static inline dev_t bstat(const char *name)
+{
+ struct stat st;
+
+ if (stat(name, &st) || !S_ISBLK(st.st_mode))
+ return 0;
+ return st.st_rdev;
+}
+
+int load_ramdisk_compressed(const char *devpath, FILE * wfd,
+ off_t ramdisk_start);
+
+#endif /* DO_MOUNTS_H */
diff --git a/usr/kinit/do_mounts_md.c b/usr/kinit/do_mounts_md.c
new file mode 100644
index 0000000..f446620
--- /dev/null
+++ b/usr/kinit/do_mounts_md.c
@@ -0,0 +1,400 @@
+/*
+ * Handle autoconfiguration of md devices. This is ugly, partially since
+ * it still relies on a sizable kernel component.
+ *
+ * This file is derived from the Linux kernel.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/sysmacros.h>
+#include <sys/md.h>
+#include <linux/major.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+
+#define LEVEL_NONE (-1000000)
+
+/*
+ * When md (and any require personalities) are compiled into the kernel
+ * (not a module), arrays can be assembles are boot time using with AUTODETECT
+ * where specially marked partitions are registered with md_autodetect_dev(),
+ * and with MD_BOOT where devices to be collected are given on the boot line
+ * with md=.....
+ * The code for that is here.
+ */
+
+static int raid_noautodetect, raid_autopart;
+
+static struct {
+ int minor;
+ int partitioned;
+ int level;
+ int chunk;
+ char *device_names;
+} md_setup_args[MAX_MD_DEVS];
+
+static int md_setup_ents;
+
+/**
+ * get_option - Parse integer from an option string
+ * @str: option string
+ * @pint: (output) integer value parsed from @str
+ *
+ * Read an int from an option string; if available accept a subsequent
+ * comma as well.
+ *
+ * Return values:
+ * 0 : no int in string
+ * 1 : int found, no subsequent comma
+ * 2 : int found including a subsequent comma
+ */
+
+static int get_option(char **str, int *pint)
+{
+ char *cur = *str;
+
+ if (!cur || !(*cur))
+ return 0;
+ *pint = strtol(cur, str, 0);
+ if (cur == *str)
+ return 0;
+ if (**str == ',') {
+ (*str)++;
+ return 2;
+ }
+
+ return 1;
+}
+
+/*
+ * Find the partitioned md device major number... of course this *HAD*
+ * to be done dynamically instead of using a registered number.
+ * Sigh. Double sigh.
+ */
+static int mdp_major(void)
+{
+ static int found = 0;
+ FILE *f;
+ char line[512], *p;
+ int is_blk, major_no;
+
+ if (found)
+ return found;
+
+ f = fopen("/proc/devices", "r");
+ is_blk = 0;
+ while (fgets(line, sizeof line, f)) {
+ if (!strcmp(line, "Block devices:\n"))
+ is_blk = 1;
+ if (is_blk) {
+ major_no = strtol(line, &p, 10);
+ while (*p && isspace(*p))
+ p++;
+
+ if (major_no == 0) /* Not a number */
+ is_blk = 0;
+ else if (major_no > 0 && !strcmp(p, "mdp")) {
+ found = major_no;
+ break;
+ }
+ }
+ }
+ fclose(f);
+
+ if (!found) {
+ fprintf(stderr,
+ "Error: mdp devices detected but no mdp device found!\n");
+ exit(1);
+ }
+
+ return found;
+}
+
+/*
+ * Parse the command-line parameters given our kernel, but do not
+ * actually try to invoke the MD device now; that is handled by
+ * md_setup_drive after the low-level disk drivers have initialised.
+ *
+ * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which
+ * assigns the task of parsing integer arguments to the
+ * invoked program now). Added ability to initialise all
+ * the MD devices (by specifying multiple "md=" lines)
+ * instead of just one. -- KTK
+ * 18May2000: Added support for persistent-superblock arrays:
+ * md=n,0,factor,fault,device-list uses RAID0 for device n
+ * md=n,-1,factor,fault,device-list uses LINEAR for device n
+ * md=n,device-list reads a RAID superblock from the devices
+ * elements in device-list are read by name_to_kdev_t so can be
+ * a hex number or something like /dev/hda1 /dev/sdb
+ * 2001-06-03: Dave Cinege <dcinege@psychosis.com>
+ * Shifted name_to_kdev_t() and related operations to md_set_drive()
+ * for later execution. Rewrote section to make devfs compatible.
+ */
+static int md_setup(char *str)
+{
+ int minor_num, level, factor, fault, partitioned = 0;
+ char *pername = "";
+ char *str1;
+ int ent;
+
+ if (*str == 'd') {
+ partitioned = 1;
+ str++;
+ }
+ if (get_option(&str, &minor_num) != 2) { /* MD Number */
+ fprintf(stderr, "md: Too few arguments supplied to md=.\n");
+ return 0;
+ }
+ str1 = str;
+ if (minor_num >= MAX_MD_DEVS) {
+ fprintf(stderr, "md: md=%d, Minor device number too high.\n",
+ minor_num);
+ return 0;
+ }
+ for (ent = 0; ent < md_setup_ents; ent++)
+ if (md_setup_args[ent].minor == minor_num &&
+ md_setup_args[ent].partitioned == partitioned) {
+ fprintf(stderr,
+ "md: md=%s%d, Specified more than once. "
+ "Replacing previous definition.\n",
+ partitioned ? "d" : "", minor_num);
+ break;
+ }
+ if (ent >= MAX_MD_DEVS) {
+ fprintf(stderr, "md: md=%s%d - too many md initialisations\n",
+ partitioned ? "d" : "", minor_num);
+ return 0;
+ }
+ if (ent >= md_setup_ents)
+ md_setup_ents++;
+ switch (get_option(&str, &level)) { /* RAID level */
+ case 2: /* could be 0 or -1.. */
+ if (level == 0 || level == LEVEL_LINEAR) {
+ if (get_option(&str, &factor) != 2 || /* Chunk Size */
+ get_option(&str, &fault) != 2) {
+ fprintf(stderr,
+ "md: Too few arguments supplied to md=.\n");
+ return 0;
+ }
+ md_setup_args[ent].level = level;
+ md_setup_args[ent].chunk = 1 << (factor + 12);
+ if (level == LEVEL_LINEAR)
+ pername = "linear";
+ else
+ pername = "raid0";
+ break;
+ }
+ /* FALL THROUGH */
+ case 1: /* the first device is numeric */
+ str = str1;
+ /* FALL THROUGH */
+ case 0:
+ md_setup_args[ent].level = LEVEL_NONE;
+ pername = "super-block";
+ }
+
+ fprintf(stderr, "md: Will configure md%s%d (%s) from %s, below.\n",
+ partitioned ? "_d" : "", minor_num, pername, str);
+ md_setup_args[ent].device_names = str;
+ md_setup_args[ent].partitioned = partitioned;
+ md_setup_args[ent].minor = minor_num;
+
+ return 1;
+}
+
+#define MdpMinorShift 6
+
+static void md_setup_drive(void)
+{
+ int dev_minor, i, ent, partitioned;
+ dev_t dev;
+ dev_t devices[MD_SB_DISKS + 1];
+
+ for (ent = 0; ent < md_setup_ents; ent++) {
+ int fd;
+ int err = 0;
+ char *devname;
+ mdu_disk_info_t dinfo;
+ char name[16];
+ struct stat st_chk;
+
+ dev_minor = md_setup_args[ent].minor;
+ partitioned = md_setup_args[ent].partitioned;
+ devname = md_setup_args[ent].device_names;
+
+ snprintf(name, sizeof name,
+ "/dev/md%s%d", partitioned ? "_d" : "", dev_minor);
+
+ if (stat(name, &st_chk) == 0)
+ continue;
+
+ if (partitioned)
+ dev = makedev(mdp_major(), dev_minor << MdpMinorShift);
+ else
+ dev = makedev(MD_MAJOR, dev_minor);
+ create_dev(name, dev);
+ for (i = 0; i < MD_SB_DISKS && devname != 0; i++) {
+ char *p;
+
+ p = strchr(devname, ',');
+ if (p)
+ *p++ = 0;
+
+ dev = name_to_dev_t(devname);
+ if (!dev) {
+ fprintf(stderr, "md: Unknown device name: %s\n",
+ devname);
+ break;
+ }
+
+ devices[i] = dev;
+
+ devname = p;
+ }
+ devices[i] = 0;
+
+ if (!i)
+ continue;
+
+ fprintf(stderr, "md: Loading md%s%d: %s\n",
+ partitioned ? "_d" : "", dev_minor,
+ md_setup_args[ent].device_names);
+
+ fd = open(name, 0, 0);
+ if (fd < 0) {
+ fprintf(stderr, "md: open failed - cannot start "
+ "array %s\n", name);
+ continue;
+ }
+ if (ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) {
+ fprintf(stderr,
+ "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n",
+ dev_minor);
+ close(fd);
+ continue;
+ }
+
+ if (md_setup_args[ent].level != LEVEL_NONE) {
+ /* non-persistent */
+ mdu_array_info_t ainfo;
+ ainfo.level = md_setup_args[ent].level;
+ ainfo.size = 0;
+ ainfo.nr_disks = 0;
+ ainfo.raid_disks = 0;
+ while (devices[ainfo.raid_disks])
+ ainfo.raid_disks++;
+ ainfo.md_minor = dev_minor;
+ ainfo.not_persistent = 1;
+
+ ainfo.state = (1 << MD_SB_CLEAN);
+ ainfo.layout = 0;
+ ainfo.chunk_size = md_setup_args[ent].chunk;
+ err = ioctl(fd, SET_ARRAY_INFO, &ainfo);
+ for (i = 0; !err && i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (!dev)
+ break;
+ dinfo.number = i;
+ dinfo.raid_disk = i;
+ dinfo.state =
+ (1 << MD_DISK_ACTIVE) | (1 << MD_DISK_SYNC);
+ dinfo.major = major(dev);
+ dinfo.minor = minor(dev);
+ err = ioctl(fd, ADD_NEW_DISK, &dinfo);
+ }
+ } else {
+ /* persistent */
+ for (i = 0; i <= MD_SB_DISKS; i++) {
+ dev = devices[i];
+ if (!dev)
+ break;
+ dinfo.major = major(dev);
+ dinfo.minor = minor(dev);
+ ioctl(fd, ADD_NEW_DISK, &dinfo);
+ }
+ }
+ if (!err)
+ err = ioctl(fd, RUN_ARRAY, 0);
+ if (err)
+ fprintf(stderr, "md: starting md%d failed\n",
+ dev_minor);
+ else {
+ /* reread the partition table.
+ * I (neilb) and not sure why this is needed, but I
+ * cannot boot a kernel with devfs compiled in from
+ * partitioned md array without it
+ */
+ close(fd);
+ fd = open(name, 0, 0);
+ ioctl(fd, BLKRRPART, 0);
+ }
+ close(fd);
+ }
+}
+
+static int raid_setup(char *str)
+{
+ int len, pos;
+
+ len = strlen(str) + 1;
+ pos = 0;
+
+ while (pos < len) {
+ char *comma = strchr(str + pos, ',');
+ int wlen;
+ if (comma)
+ wlen = (comma - str) - pos;
+ else
+ wlen = (len - 1) - pos;
+
+ if (!strncmp(str, "noautodetect", wlen))
+ raid_noautodetect = 1;
+ if (strncmp(str, "partitionable", wlen) == 0)
+ raid_autopart = 1;
+ if (strncmp(str, "part", wlen) == 0)
+ raid_autopart = 1;
+ pos += wlen + 1;
+ }
+ return 1;
+}
+
+static void md_run_setup(void)
+{
+ create_dev("/dev/md0", makedev(MD_MAJOR, 0));
+ if (raid_noautodetect)
+ fprintf(stderr,
+ "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
+ else {
+ int fd = open("/dev/md0", 0, 0);
+ if (fd >= 0) {
+ ioctl(fd, RAID_AUTORUN,
+ (void *)(intptr_t) raid_autopart);
+ close(fd);
+ }
+ }
+ md_setup_drive();
+}
+
+void md_run(int argc, char *argv[])
+{
+ char **pp, *p;
+
+ for (pp = argv; (p = *pp); pp++) {
+ if (!strncmp(p, "raid=", 5))
+ raid_setup(p + 5);
+ else if (!strncmp(p, "md=", 3))
+ md_setup(p + 3);
+ }
+
+ md_run_setup();
+}
diff --git a/usr/kinit/do_mounts_mtd.c b/usr/kinit/do_mounts_mtd.c
new file mode 100644
index 0000000..20d27ca
--- /dev/null
+++ b/usr/kinit/do_mounts_mtd.c
@@ -0,0 +1,42 @@
+/*
+ * Mount an MTD device as a character device.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+
+int mount_mtd_root(int argc, char *argv[], const char *root_dev_name,
+ const char *type, unsigned long flags)
+{
+ const char *data = get_arg(argc, argv, "rootflags=");
+
+ if (!type)
+ type = "jffs2";
+
+ printf("Trying to mount MTD %s as root (%s filesystem)\n",
+ root_dev_name, type);
+
+ if (mount(root_dev_name, "/root", type, flags, data)) {
+ int err = errno;
+ fprintf(stderr,
+ "%s: Unable to mount MTD %s (%s filesystem) "
+ "as root: %s\n",
+ progname, root_dev_name, type, strerror(err));
+ return -err;
+ } else {
+ fprintf(stderr, "%s: Mounted root (%s filesystem)%s.\n",
+ progname, type, (flags & MS_RDONLY) ? " readonly" : "");
+ return 0;
+ }
+
+}
diff --git a/usr/kinit/fstype/Kbuild b/usr/kinit/fstype/Kbuild
new file mode 100644
index 0000000..631eb32
--- /dev/null
+++ b/usr/kinit/fstype/Kbuild
@@ -0,0 +1,29 @@
+#
+# Kbuild file for fstype
+#
+
+static-y := static/fstype
+shared-y := shared/fstype
+
+# common .o files
+objs := main.o fstype.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/fstype-y := $(objs)
+shared/fstype-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
diff --git a/usr/kinit/fstype/btrfs.h b/usr/kinit/fstype/btrfs.h
new file mode 100644
index 0000000..459da12
--- /dev/null
+++ b/usr/kinit/fstype/btrfs.h
@@ -0,0 +1,57 @@
+#ifndef __BTRFS_H
+#define __BTRFS_H
+
+# define BTRFS_MAGIC "_BHRfS_M"
+# define BTRFS_MAGIC_L 8
+
+/*
+ * Structure of the super block
+ */
+struct btrfs_super_block {
+ uint8_t csum[32];
+ uint8_t fsid[16];
+ uint64_t bytenr;
+ uint64_t flags;
+ uint8_t magic[8];
+ uint64_t generation;
+ uint64_t root;
+ uint64_t chunk_root;
+ uint64_t log_root;
+ uint64_t log_root_transid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint64_t root_dir_objectid;
+ uint64_t num_devices;
+ uint32_t sectorsize;
+ uint32_t nodesize;
+ uint32_t leafsize;
+ uint32_t stripesize;
+ uint32_t sys_chunk_array_size;
+ uint64_t chunk_root_generation;
+ uint64_t compat_flags;
+ uint64_t compat_ro_flags;
+ uint64_t incompat_flags;
+ uint16_t csum_type;
+ uint8_t root_level;
+ uint8_t chunk_root_level;
+ uint8_t log_root_level;
+ struct btrfs_dev_item {
+ uint64_t devid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint32_t io_align;
+ uint32_t io_width;
+ uint32_t sector_size;
+ uint64_t type;
+ uint64_t generation;
+ uint64_t start_offset;
+ uint32_t dev_group;
+ uint8_t seek_speed;
+ uint8_t bandwidth;
+ uint8_t uuid[16];
+ uint8_t fsid[16];
+ } __attribute__ ((__packed__)) dev_item;
+ uint8_t label[256];
+} __attribute__ ((__packed__));
+
+#endif /* __BTRFS_H */
diff --git a/usr/kinit/fstype/cramfs_fs.h b/usr/kinit/fstype/cramfs_fs.h
new file mode 100644
index 0000000..6f5ad4f
--- /dev/null
+++ b/usr/kinit/fstype/cramfs_fs.h
@@ -0,0 +1,85 @@
+#ifndef __CRAMFS_H
+#define __CRAMFS_H
+
+#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */
+#define CRAMFS_SIGNATURE "Compressed ROMFS"
+
+/*
+ * Width of various bitfields in struct cramfs_inode.
+ * Primarily used to generate warnings in mkcramfs.
+ */
+#define CRAMFS_MODE_WIDTH 16
+#define CRAMFS_UID_WIDTH 16
+#define CRAMFS_SIZE_WIDTH 24
+#define CRAMFS_GID_WIDTH 8
+#define CRAMFS_NAMELEN_WIDTH 6
+#define CRAMFS_OFFSET_WIDTH 26
+
+/*
+ * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs
+ * path length is 63 << 2 = 252.
+ */
+#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2)
+
+/*
+ * Reasonably terse representation of the inode data.
+ */
+struct cramfs_inode {
+ __u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH;
+ /* SIZE for device files is i_rdev */
+ __u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH;
+ /* NAMELEN is the length of the file name, divided by 4 and
+ rounded up. (cramfs doesn't support hard links.) */
+ /* OFFSET: For symlinks and non-empty regular files, this
+ contains the offset (divided by 4) of the file data in
+ compressed form (starting with an array of block pointers;
+ see README). For non-empty directories it is the offset
+ (divided by 4) of the inode of the first file in that
+ directory. For anything else, offset is zero. */
+ __u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH;
+};
+
+struct cramfs_info {
+ __u32 crc;
+ __u32 edition;
+ __u32 blocks;
+ __u32 files;
+};
+
+/*
+ * Superblock information at the beginning of the FS.
+ */
+struct cramfs_super {
+ __u32 magic; /* 0x28cd3d45 - random number */
+ __u32 size; /* length in bytes */
+ __u32 flags; /* feature flags */
+ __u32 future; /* reserved for future use */
+ __u8 signature[16]; /* "Compressed ROMFS" */
+ struct cramfs_info fsid; /* unique filesystem info */
+ __u8 name[16]; /* user-defined name */
+ struct cramfs_inode root; /* root inode data */
+};
+
+/*
+ * Feature flags
+ *
+ * 0x00000000 - 0x000000ff: features that work for all past kernels
+ * 0x00000100 - 0xffffffff: features that don't work for past kernels
+ */
+#define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */
+#define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */
+#define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */
+#define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */
+#define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */
+
+/*
+ * Valid values in super.flags. Currently we refuse to mount
+ * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be
+ * changed to test super.future instead.
+ */
+#define CRAMFS_SUPPORTED_FLAGS ( 0x000000ff \
+ | CRAMFS_FLAG_HOLES \
+ | CRAMFS_FLAG_WRONG_SIGNATURE \
+ | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET )
+
+#endif
diff --git a/usr/kinit/fstype/ext2_fs.h b/usr/kinit/fstype/ext2_fs.h
new file mode 100644
index 0000000..775df8f
--- /dev/null
+++ b/usr/kinit/fstype/ext2_fs.h
@@ -0,0 +1,84 @@
+#ifndef __EXT2_FS_H
+#define __EXT2_FS_H
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __le32 s_inodes_count; /* Inodes count */
+ __le32 s_blocks_count; /* Blocks count */
+ __le32 s_r_blocks_count; /* Reserved blocks count */
+ __le32 s_free_blocks_count; /* Free blocks count */
+ __le32 s_free_inodes_count; /* Free inodes count */
+ __le32 s_first_data_block; /* First Data Block */
+ __le32 s_log_block_size; /* Block size */
+ __le32 s_log_frag_size; /* Fragment size */
+ __le32 s_blocks_per_group; /* # Blocks per group */
+ __le32 s_frags_per_group; /* # Fragments per group */
+ __le32 s_inodes_per_group; /* # Inodes per group */
+ __le32 s_mtime; /* Mount time */
+ __le32 s_wtime; /* Write time */
+ __le16 s_mnt_count; /* Mount count */
+ __le16 s_max_mnt_count; /* Maximal mount count */
+ __le16 s_magic; /* Magic signature */
+ __le16 s_state; /* File system state */
+ __le16 s_errors; /* Behaviour when detecting errors */
+ __le16 s_minor_rev_level; /* minor revision level */
+ __le32 s_lastcheck; /* time of last check */
+ __le32 s_checkinterval; /* max. time between checks */
+ __le32 s_creator_os; /* OS */
+ __le32 s_rev_level; /* Revision level */
+ __le16 s_def_resuid; /* Default uid for reserved blocks */
+ __le16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __le32 s_first_ino; /* First non-reserved inode */
+ __le16 s_inode_size; /* size of inode structure */
+ __le16 s_block_group_nr; /* block group # of this superblock */
+ __le32 s_feature_compat; /* compatible feature set */
+ __le32 s_feature_incompat; /* incompatible feature set */
+ __le32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __le32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate */
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ /*
+ * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
+ __u32 s_journal_inum; /* inode number of journal file */
+ __u32 s_journal_dev; /* device number of journal file */
+ __u32 s_last_orphan; /* start of list of inodes to delete */
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_reserved_char_pad;
+ __u16 s_reserved_word_pad;
+ __le32 s_default_mount_opts;
+ __le32 s_first_meta_bg; /* First metablock block group */
+ __u32 s_reserved[190]; /* Padding to the end of the block */
+};
+
+#endif /* __EXT2_FS_H */
diff --git a/usr/kinit/fstype/ext3_fs.h b/usr/kinit/fstype/ext3_fs.h
new file mode 100644
index 0000000..f958e5c
--- /dev/null
+++ b/usr/kinit/fstype/ext3_fs.h
@@ -0,0 +1,134 @@
+#ifndef __EXT3_FS_H
+#define __EXT3_FS_H
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT3_SUPER_MAGIC 0xEF53
+
+#define EXT2_FLAGS_TEST_FILESYS 0x0004
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+
+#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+
+#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT3_FEATURE_RO_COMPAT_SUPP
+#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+ EXT3_FEATURE_INCOMPAT_RECOVER| \
+ EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED ~EXT3_FEATURE_INCOMPAT_SUPP
+
+
+
+/*
+ * Structure of the super block
+ */
+struct ext3_super_block {
+ /*00*/ __u32 s_inodes_count;
+ /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ /*10*/ __u32 s_free_inodes_count;
+ /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __s32 s_log_frag_size; /* Fragment size */
+ /*20*/ __u32 s_blocks_per_group;
+ /* # Blocks per group */
+ __u32 s_frags_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ /*30*/ __u32 s_wtime;
+ /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ /*40*/ __u32 s_lastcheck;
+ /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ /*50*/ __u16 s_def_resuid;
+ /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT3_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ /*60*/ __u32 s_feature_incompat;
+ /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ /*68*/ __u8 s_uuid[16];
+ /* 128-bit uuid for volume */
+ /*78*/ char s_volume_name[16];
+ /* volume name */
+ /*88*/ char s_last_mounted[64];
+ /* directory where last mounted */
+ /*C8*/ __u32 s_algorithm_usage_bitmap;
+ /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate */
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ /*
+ * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ /*D0*/ __u8 s_journal_uuid[16];
+ /* uuid of journal superblock */
+ /*E0*/ __u32 s_journal_inum;
+ /* inode number of journal file */
+ __u32 s_journal_dev; /* device number of journal file */
+ __u32 s_last_orphan; /* start of list of inodes to delete */
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_jnl_backup_type;
+ __u16 s_reserved_word_pad;
+ __u32 s_default_mount_opts;
+ __u32 s_first_meta_bg;
+ __u32 s_mkfs_time;
+ __u32 s_jnl_blocks[17];
+ __u32 s_blocks_count_hi;
+ __u32 s_r_blocks_count_hi;
+ __u32 s_free_blocks_hi;
+ __u16 s_min_extra_isize;
+ __u16 s_want_extra_isize;
+ __u32 s_flags;
+ __u16 s_raid_stride;
+ __u16 s_mmp_interval;
+ __u64 s_mmp_block;
+ __u32 s_raid_stripe_width;
+ __u32 s_reserved[163];
+};
+
+#endif /* __EXT3_FS_H */
diff --git a/usr/kinit/fstype/fstype.c b/usr/kinit/fstype/fstype.c
new file mode 100644
index 0000000..aebccca
--- /dev/null
+++ b/usr/kinit/fstype/fstype.c
@@ -0,0 +1,445 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ * FSTYPE - filesystem type
+ * FSSIZE - filesystem size (if known)
+ *
+ * We currently detect the filesystems listed below in the struct
+ * "imagetype images" (in the order they are listed).
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <endian.h>
+#include <netinet/in.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+
+#define cpu_to_be32(x) __cpu_to_be32(x) /* Needed by romfs_fs.h */
+
+#include "btrfs.h"
+#include "cramfs_fs.h"
+#include "ext2_fs.h"
+#include "ext3_fs.h"
+#include "gfs2_fs.h"
+#include "iso9660_sb.h"
+#include "luks_fs.h"
+#include "lvm2_sb.h"
+#include "minix_fs.h"
+#include "nilfs_fs.h"
+#include "ocfs2_fs.h"
+#include "romfs_fs.h"
+#include "squashfs_fs.h"
+#include "xfs_sb.h"
+
+/*
+ * Slightly cleaned up version of jfs_superblock to
+ * avoid pulling in other kernel header files.
+ */
+#include "jfs_superblock.h"
+
+/*
+ * reiserfs_fs.h is too sick to include directly.
+ * Use a cleaned up version.
+ */
+#include "reiserfs_fs.h"
+#include "reiser4_fs.h"
+
+#include "fstype.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+#define BLOCK_SIZE 1024
+
+/* Swap needs the definition of block size */
+#include "swap_fs.h"
+
+static int gzip_image(const void *buf, unsigned long long *bytes)
+{
+ const unsigned char *p = buf;
+
+ if (p[0] == 037 && (p[1] == 0213 || p[1] == 0236)) {
+ /* The length of a gzip stream can only be determined
+ by processing the whole stream */
+ *bytes = 0ULL;
+ return 1;
+ }
+ return 0;
+}
+
+static int cramfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct cramfs_super *sb = (const struct cramfs_super *)buf;
+
+ if (sb->magic == CRAMFS_MAGIC) {
+ if (sb->flags & CRAMFS_FLAG_FSID_VERSION_2)
+ *bytes = (unsigned long long)sb->fsid.blocks << 10;
+ else
+ *bytes = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int romfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct romfs_super_block *sb =
+ (const struct romfs_super_block *)buf;
+
+ if (sb->word0 == ROMSB_WORD0 && sb->word1 == ROMSB_WORD1) {
+ *bytes = __be32_to_cpu(sb->size);
+ return 1;
+ }
+ return 0;
+}
+
+static int minix_image(const void *buf, unsigned long long *bytes)
+{
+ const struct minix_super_block *sb =
+ (const struct minix_super_block *)buf;
+
+ if (sb->s_magic == MINIX_SUPER_MAGIC ||
+ sb->s_magic == MINIX_SUPER_MAGIC2) {
+ *bytes = (unsigned long long)sb->s_nzones
+ << (sb->s_log_zone_size + 10);
+ return 1;
+ }
+ return 0;
+}
+
+static int ext4_image(const void *buf, unsigned long long *bytes)
+{
+ const struct ext3_super_block *sb =
+ (const struct ext3_super_block *)buf;
+
+ if (sb->s_magic != __cpu_to_le16(EXT2_SUPER_MAGIC))
+ return 0;
+
+ /* There is at least one feature not supported by ext3 */
+ if ((sb->s_feature_incompat
+ & __cpu_to_le32(EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) ||
+ (sb->s_feature_ro_compat
+ & __cpu_to_le32(EXT3_FEATURE_RO_COMPAT_UNSUPPORTED))) {
+ *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
+ << (10 + __le32_to_cpu(sb->s_log_block_size));
+ return 1;
+ }
+ return 0;
+}
+
+static int ext3_image(const void *buf, unsigned long long *bytes)
+{
+ const struct ext3_super_block *sb =
+ (const struct ext3_super_block *)buf;
+
+ if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC) &&
+ sb->
+ s_feature_compat & __cpu_to_le32(EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+ *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
+ << (10 + __le32_to_cpu(sb->s_log_block_size));
+ return 1;
+ }
+ return 0;
+}
+
+static int ext2_image(const void *buf, unsigned long long *bytes)
+{
+ const struct ext2_super_block *sb =
+ (const struct ext2_super_block *)buf;
+
+ if (sb->s_magic == __cpu_to_le16(EXT2_SUPER_MAGIC)) {
+ *bytes = (unsigned long long)__le32_to_cpu(sb->s_blocks_count)
+ << (10 + __le32_to_cpu(sb->s_log_block_size));
+ return 1;
+ }
+ return 0;
+}
+
+static int reiserfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct reiserfs_super_block *sb =
+ (const struct reiserfs_super_block *)buf;
+
+ if (memcmp(REISERFS_MAGIC(sb), REISERFS_SUPER_MAGIC_STRING,
+ sizeof(REISERFS_SUPER_MAGIC_STRING) - 1) == 0 ||
+ memcmp(REISERFS_MAGIC(sb), REISER2FS_SUPER_MAGIC_STRING,
+ sizeof(REISER2FS_SUPER_MAGIC_STRING) - 1) == 0 ||
+ memcmp(REISERFS_MAGIC(sb), REISER2FS_JR_SUPER_MAGIC_STRING,
+ sizeof(REISER2FS_JR_SUPER_MAGIC_STRING) - 1) == 0) {
+ *bytes = (unsigned long long)REISERFS_BLOCK_COUNT(sb) *
+ REISERFS_BLOCKSIZE(sb);
+ return 1;
+ }
+ return 0;
+}
+
+static int reiser4_image(const void *buf, unsigned long long *bytes)
+{
+ const struct reiser4_master_sb *sb =
+ (const struct reiser4_master_sb *)buf;
+
+ if (memcmp(sb->ms_magic, REISER4_SUPER_MAGIC_STRING,
+ sizeof(REISER4_SUPER_MAGIC_STRING) - 1) == 0) {
+ *bytes = (unsigned long long) __le32_to_cpu(sb->ms_format) *
+ __le32_to_cpu(sb->ms_blksize);
+ return 1;
+ }
+ return 0;
+}
+
+static int xfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct xfs_sb *sb = (const struct xfs_sb *)buf;
+
+ if (__be32_to_cpu(sb->sb_magicnum) == XFS_SB_MAGIC) {
+ *bytes = __be64_to_cpu(sb->sb_dblocks) *
+ __be32_to_cpu(sb->sb_blocksize);
+ return 1;
+ }
+ return 0;
+}
+
+static int jfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct jfs_superblock *sb = (const struct jfs_superblock *)buf;
+
+ if (!memcmp(sb->s_magic, JFS_MAGIC, 4)) {
+ *bytes = __le64_to_cpu(sb->s_size)
+ << __le16_to_cpu(sb->s_l2pbsize);
+ return 1;
+ }
+ return 0;
+}
+
+static int luks_image(const void *buf, unsigned long long *blocks)
+{
+ const struct luks_partition_header *lph =
+ (const struct luks_partition_header *)buf;
+
+ if (!memcmp(lph->magic, LUKS_MAGIC, LUKS_MAGIC_L)) {
+ /* FSSIZE is dictated by the underlying fs, not by LUKS */
+ *blocks = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int swap_image(const void *buf, unsigned long long *blocks)
+{
+ const struct swap_super_block *ssb =
+ (const struct swap_super_block *)buf;
+
+ if (!memcmp(ssb->magic, SWAP_MAGIC_1, SWAP_MAGIC_L) ||
+ !memcmp(ssb->magic, SWAP_MAGIC_2, SWAP_MAGIC_L)) {
+ *blocks = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int suspend_image(const void *buf, unsigned long long *blocks)
+{
+ const struct swap_super_block *ssb =
+ (const struct swap_super_block *)buf;
+
+ if (!memcmp(ssb->magic, SUSP_MAGIC_1, SUSP_MAGIC_L) ||
+ !memcmp(ssb->magic, SUSP_MAGIC_2, SUSP_MAGIC_L) ||
+ !memcmp(ssb->magic, SUSP_MAGIC_U, SUSP_MAGIC_L)) {
+ *blocks = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int lvm2_image(const void *buf, unsigned long long *blocks)
+{
+ const struct lvm2_super_block *lsb;
+ int i;
+
+ /* We must check every 512 byte sector */
+ for (i = 0; i < BLOCK_SIZE; i += 0x200) {
+ lsb = (const struct lvm2_super_block *)(buf + i);
+
+ if (!memcmp(lsb->magic, LVM2_MAGIC, LVM2_MAGIC_L) &&
+ !memcmp(lsb->type, LVM2_TYPE, LVM2_TYPE_L)) {
+ /* This is just one of possibly many PV's */
+ *blocks = 0;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int iso_image(const void *buf, unsigned long long *blocks)
+{
+ const struct iso_volume_descriptor *isovd =
+ (const struct iso_volume_descriptor *)buf;
+ const struct iso_hs_volume_descriptor *isohsvd =
+ (const struct iso_hs_volume_descriptor *)buf;
+
+ if (!memcmp(isovd->id, ISO_MAGIC, ISO_MAGIC_L) ||
+ !memcmp(isohsvd->id, ISO_HS_MAGIC, ISO_HS_MAGIC_L)) {
+ *blocks = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int squashfs_image(const void *buf, unsigned long long *blocks)
+{
+ const struct squashfs_super_block *sb =
+ (const struct squashfs_super_block *)buf;
+
+ if (sb->s_magic == SQUASHFS_MAGIC
+ || sb->s_magic == SQUASHFS_MAGIC_SWAP
+ || sb->s_magic == SQUASHFS_MAGIC_LZMA
+ || sb->s_magic == SQUASHFS_MAGIC_LZMA_SWAP) {
+ *blocks = (unsigned long long) sb->bytes_used;
+ return 1;
+ }
+ return 0;
+}
+
+static int gfs2_image(const void *buf, unsigned long long *bytes)
+{
+ const struct gfs2_sb *sb =
+ (const struct gfs2_sb *)buf;
+
+ if (__be32_to_cpu(sb->sb_header.mh_magic) == GFS2_MAGIC
+ && (__be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_FS
+ || __be32_to_cpu(sb->sb_fs_format) == GFS2_FORMAT_MULTI)) {
+ *bytes = 0; /* cpu_to_be32(sb->sb_bsize) * ?; */
+ return 1;
+ }
+ return 0;
+}
+
+static int ocfs2_image(const void *buf, unsigned long long *bytes)
+{
+ const struct ocfs2_dinode *sb =
+ (const struct ocfs2_dinode *)buf;
+
+ if (!memcmp(sb->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE,
+ sizeof(OCFS2_SUPER_BLOCK_SIGNATURE) - 1)) {
+ *bytes = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int nilfs2_image(const void *buf, unsigned long long *bytes)
+{
+ const struct nilfs_super_block *sb =
+ (const struct nilfs_super_block *)buf;
+
+ if (sb->s_magic == __cpu_to_le16(NILFS_SUPER_MAGIC) &&
+ sb->s_rev_level == __cpu_to_le32(2)) {
+ *bytes = (unsigned long long)__le64_to_cpu(sb->s_dev_size);
+ return 1;
+ }
+ return 0;
+}
+
+static int btrfs_image(const void *buf, unsigned long long *bytes)
+{
+ const struct btrfs_super_block *sb =
+ (const struct btrfs_super_block *)buf;
+
+ if (!memcmp(sb->magic, BTRFS_MAGIC, BTRFS_MAGIC_L)) {
+ *bytes = (unsigned long long)__le64_to_cpu(sb->total_bytes);
+ return 1;
+ }
+ return 0;
+}
+
+struct imagetype {
+ off_t block;
+ const char name[12];
+ int (*identify) (const void *, unsigned long long *);
+};
+
+/*
+ * Note:
+ *
+ * Minix test needs to come after ext3/ext2, since it's possible for
+ * ext3/ext2 to look like minix by pure random chance.
+ *
+ * LVM comes after all other filesystems since it's possible
+ * that an old lvm signature is left on the disk if pvremove
+ * is not used before creating the new fs.
+ *
+ * The same goes for LUKS as for LVM.
+ */
+static struct imagetype images[] = {
+ {0, "gzip", gzip_image},
+ {0, "cramfs", cramfs_image},
+ {0, "romfs", romfs_image},
+ {0, "xfs", xfs_image},
+ {0, "squashfs", squashfs_image},
+ {1, "ext4", ext4_image},
+ {1, "ext3", ext3_image},
+ {1, "ext2", ext2_image},
+ {1, "minix", minix_image},
+ {1, "nilfs2", nilfs2_image},
+ {2, "ocfs2", ocfs2_image},
+ {8, "reiserfs", reiserfs_image},
+ {64, "reiserfs", reiserfs_image},
+ {64, "reiser4", reiser4_image},
+ {64, "gfs2", gfs2_image},
+ {64, "btrfs", btrfs_image},
+ {32, "jfs", jfs_image},
+ {32, "iso9660", iso_image},
+ {0, "luks", luks_image},
+ {0, "lvm2", lvm2_image},
+ {1, "lvm2", lvm2_image},
+ {-1, "swap", swap_image},
+ {-1, "suspend", suspend_image},
+ {0, "", NULL}
+};
+
+int identify_fs(int fd, const char **fstype,
+ unsigned long long *bytes, off_t offset)
+{
+ uint64_t buf[BLOCK_SIZE >> 3]; /* 64-bit worst case alignment */
+ off_t cur_block = (off_t) -1;
+ struct imagetype *ip;
+ int ret;
+ unsigned long long dummy;
+
+ if (!bytes)
+ bytes = &dummy;
+
+ *fstype = NULL;
+ *bytes = 0;
+
+ for (ip = images; ip->identify; ip++) {
+ /* Hack for swap, which apparently is dependent on page size */
+ if (ip->block == -1)
+ ip->block = SWAP_OFFSET();
+
+ if (cur_block != ip->block) {
+ /*
+ * Read block.
+ */
+ cur_block = ip->block;
+ ret = pread(fd, buf, BLOCK_SIZE,
+ offset + cur_block * BLOCK_SIZE);
+ if (ret != BLOCK_SIZE)
+ return -1; /* error */
+ }
+
+ if (ip->identify(buf, bytes)) {
+ *fstype = ip->name;
+ return 0;
+ }
+ }
+
+ return 1; /* Unknown filesystem */
+}
diff --git a/usr/kinit/fstype/fstype.h b/usr/kinit/fstype/fstype.h
new file mode 100644
index 0000000..be2a3e4
--- /dev/null
+++ b/usr/kinit/fstype/fstype.h
@@ -0,0 +1,20 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ * FSTYPE - filesystem type
+ * FSSIZE - filesystem size (if known)
+ *
+ * We currently detect the fs listed in struct imagetype.
+ */
+
+#ifndef FSTYPE_H
+#define FSTYPE_H
+
+#include <unistd.h>
+
+int identify_fs(int fd, const char **fstype,
+ unsigned long long *bytes, off_t offset);
+
+#endif
diff --git a/usr/kinit/fstype/gfs2_fs.h b/usr/kinit/fstype/gfs2_fs.h
new file mode 100644
index 0000000..028e0c9
--- /dev/null
+++ b/usr/kinit/fstype/gfs2_fs.h
@@ -0,0 +1,56 @@
+#ifndef __GFS2_FS_H
+#define __GFS2_FS_H
+
+#define GFS2_MAGIC 0x01161970
+#define GFS2_FORMAT_FS 1801
+#define GFS2_FORMAT_MULTI 1900
+
+
+/*
+ * An on-disk inode number
+ */
+struct gfs2_inum {
+ __be64 no_formal_ino;
+ __be64 no_addr;
+};
+
+/*
+ * Generic metadata head structure
+ * Every inplace buffer logged in the journal must start with this.
+ */
+struct gfs2_meta_header {
+ uint32_t mh_magic;
+ uint32_t mh_type;
+ uint64_t __pad0; /* Was generation number in gfs1 */
+ uint32_t mh_format;
+ uint32_t __pad1; /* Was incarnation number in gfs1 */
+};
+
+/* Requirement: GFS2_LOCKNAME_LEN % 8 == 0
+ * Includes: the fencing zero at the end */
+#define GFS2_LOCKNAME_LEN 64
+
+/*
+ * super-block structure
+ */
+struct gfs2_sb {
+ struct gfs2_meta_header sb_header;
+
+ uint32_t sb_fs_format;
+ uint32_t sb_multihost_format;
+ uint32_t __pad0; /* Was superblock flags in gfs1 */
+
+ uint32_t sb_bsize;
+ uint32_t sb_bsize_shift;
+ uint32_t __pad1; /* Was journal segment size in gfs1 */
+
+ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+ struct gfs2_inum sb_root_dir;
+
+ char sb_lockproto[GFS2_LOCKNAME_LEN];
+ char sb_locktable[GFS2_LOCKNAME_LEN];
+ /* In gfs1, quota and license dinodes followed */
+} __attribute__ ((__packed__));
+
+#endif /* __GFS2_FS_H */
diff --git a/usr/kinit/fstype/iso9660_sb.h b/usr/kinit/fstype/iso9660_sb.h
new file mode 100644
index 0000000..efe0733
--- /dev/null
+++ b/usr/kinit/fstype/iso9660_sb.h
@@ -0,0 +1,24 @@
+#ifndef __ISO9660_SB_H
+#define __ISO9660_SB_H
+
+#define ISO_MAGIC_L 5
+#define ISO_MAGIC "CD001"
+#define ISO_HS_MAGIC_L 5
+#define ISO_HS_MAGIC "CDROM"
+
+/* ISO9660 Volume Descriptor */
+struct iso_volume_descriptor {
+ __u8 type;
+ char id[ISO_MAGIC_L];
+ __u8 version;
+};
+
+/* High Sierra Volume Descriptor */
+struct iso_hs_volume_descriptor {
+ char foo[8];
+ __u8 type;
+ char id[ISO_HS_MAGIC_L];
+ __u8 version;
+};
+
+#endif
diff --git a/usr/kinit/fstype/jfs_superblock.h b/usr/kinit/fstype/jfs_superblock.h
new file mode 100644
index 0000000..63132a0
--- /dev/null
+++ b/usr/kinit/fstype/jfs_superblock.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2000-2003
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _H_JFS_SUPERBLOCK
+#define _H_JFS_SUPERBLOCK
+
+struct timestruc_t {
+ __le32 tv_sec;
+ __le32 tv_nsec;
+};
+
+/*
+ * make the magic number something a human could read
+ */
+#define JFS_MAGIC "JFS1" /* Magic word */
+
+#define JFS_VERSION 2 /* Version number: Version 2 */
+
+#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
+
+/*
+ * aggregate superblock
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock. The utilities are still using the old name.
+ */
+struct jfs_superblock {
+ char s_magic[4]; /* 4: magic number */
+ __le32 s_version; /* 4: version number */
+
+ __le64 s_size; /* 8: aggregate size in hardware/LVM blocks;
+ * VFS: number of blocks
+ */
+ __le32 s_bsize; /* 4: aggregate block size in bytes;
+ * VFS: fragment size
+ */
+ __le16 s_l2bsize; /* 2: log2 of s_bsize */
+ __le16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
+ __le32 s_pbsize; /* 4: hardware/LVM block size in bytes */
+ __le16 s_l2pbsize; /* 2: log2 of s_pbsize */
+ __le16 pad; /* 2: padding necessary for alignment */
+
+ __le32 s_agsize; /* 4: allocation group size in aggr. blocks */
+
+ __le32 s_flag; /* 4: aggregate attributes:
+ * see jfs_filsys.h
+ */
+ __le32 s_state; /* 4: mount/unmount/recovery state:
+ * see jfs_filsys.h
+ */
+ __le32 s_compress; /* 4: > 0 if data compression */
+
+ __le64 s_ait2; /* 8: first extent of secondary
+ * aggregate inode table
+ */
+
+ __le64 s_aim2; /* 8: first extent of secondary
+ * aggregate inode map
+ */
+ __le32 s_logdev; /* 4: device address of log */
+ __le32 s_logserial; /* 4: log serial number at aggregate mount */
+ __le64 s_logpxd; /* 8: inline log extent */
+
+ __le64 s_fsckpxd; /* 8: inline fsck work space extent */
+
+ struct timestruc_t s_time; /* 8: time last updated */
+
+ __le32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for
+ * the fsck service log.
+ * N.B. These blocks are divided among the
+ * versions kept. This is not a per
+ * version size.
+ * N.B. These blocks are included in the
+ * length field of s_fsckpxd.
+ */
+ char s_fscklog; /* 1: which fsck service log is most recent
+ * 0 => no service log data yet
+ * 1 => the first one
+ * 2 => the 2nd one
+ */
+ char s_fpack[11]; /* 11: file system volume name
+ * N.B. This must be 11 bytes to
+ * conform with the OS/2 BootSector
+ * requirements
+ * Only used when s_version is 1
+ */
+
+ /* extendfs() parameter under s_state & FM_EXTENDFS */
+ __le64 s_xsize; /* 8: extendfs s_size */
+ __le64 s_xfsckpxd; /* 8: extendfs fsckpxd */
+ __le64 s_xlogpxd; /* 8: extendfs logpxd */
+ /* - 128 byte boundary - */
+
+ char s_uuid[16]; /* 16: 128-bit uuid for volume */
+ char s_label[16]; /* 16: volume label */
+ char s_loguuid[16]; /* 16: 128-bit uuid for log device */
+
+};
+
+#endif /*_H_JFS_SUPERBLOCK */
diff --git a/usr/kinit/fstype/luks_fs.h b/usr/kinit/fstype/luks_fs.h
new file mode 100644
index 0000000..fd8de31
--- /dev/null
+++ b/usr/kinit/fstype/luks_fs.h
@@ -0,0 +1,44 @@
+#ifndef __LINUX_LUKS_FS_H
+#define __LINUX_LUKS_FS_H
+
+/* The basic structures of the luks partition header */
+#define LUKS_MAGIC_L 6
+#define LUKS_CIPHERNAME_L 32
+#define LUKS_CIPHERMODE_L 32
+#define LUKS_HASHSPEC_L 32
+#define LUKS_UUID_STRING_L 40
+
+#define LUKS_MAGIC "LUKS\xBA\xBE"
+#define LUKS_DIGESTSIZE 20
+#define LUKS_SALTSIZE 32
+#define LUKS_NUMKEYS 8
+#define LUKS_MKD_ITER 10
+#define LUKS_KEY_DISABLED 0x0000DEAD
+#define LUKS_KEY_ENABLED 0x00AC71F3
+#define LUKS_STRIPES 4000
+
+/* On-disk "super block" */
+struct luks_partition_header {
+ char magic[LUKS_MAGIC_L];
+ __be16 version;
+ char cipherName[LUKS_CIPHERNAME_L];
+ char cipherMode[LUKS_CIPHERMODE_L];
+ char hashSpec[LUKS_HASHSPEC_L];
+ __be32 payloadOffset;
+ __be32 keyBytes;
+ char mkDigest[LUKS_DIGESTSIZE];
+ char mkDigestSalt[LUKS_SALTSIZE];
+ __be32 mkDigestIterations;
+ char uuid[LUKS_UUID_STRING_L];
+
+ struct {
+ __be32 active;
+ /* Parameters for PBKDF2 processing */
+ __be32 passwordIterations;
+ char passwordSalt[LUKS_SALTSIZE];
+ __be32 keyMaterialOffset;
+ __be32 stripes;
+ } keyblock[LUKS_NUMKEYS];
+};
+
+#endif
diff --git a/usr/kinit/fstype/lvm2_sb.h b/usr/kinit/fstype/lvm2_sb.h
new file mode 100644
index 0000000..75dfc10
--- /dev/null
+++ b/usr/kinit/fstype/lvm2_sb.h
@@ -0,0 +1,18 @@
+#ifndef __LVM2_SB_H
+#define __LVM2_SB_H
+
+/* LVM2 super block definitions */
+#define LVM2_MAGIC_L 8
+#define LVM2_MAGIC "LABELONE"
+#define LVM2_TYPE_L 8
+#define LVM2_TYPE "LVM2 001"
+
+struct lvm2_super_block {
+ char magic[LVM2_MAGIC_L];
+ __be64 sector;
+ __be32 crc;
+ __be32 offset;
+ char type[LVM2_TYPE_L];
+};
+
+#endif
diff --git a/usr/kinit/fstype/main.c b/usr/kinit/fstype/main.c
new file mode 100644
index 0000000..9162bdf
--- /dev/null
+++ b/usr/kinit/fstype/main.c
@@ -0,0 +1,57 @@
+/*
+ * by rmk
+ *
+ * Detect filesystem type (on stdin) and output strings for two
+ * environment variables:
+ * FSTYPE - filesystem type
+ * FSSIZE - filesystem size (if known)
+ *
+ * We currently detect (in order):
+ * gzip, cramfs, romfs, xfs, minix, ext3, ext2, reiserfs, jfs
+ *
+ * MINIX, ext3 and Reiserfs bits are currently untested.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "fstype.h"
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+ int fd = 0;
+ int rv;
+ const char *fstype;
+ const char *file = "stdin";
+ unsigned long long bytes;
+
+ progname = argv[0];
+
+ if (argc > 2) {
+ fprintf(stderr, "Usage: %s [file]\n", progname);
+ return 1;
+ }
+
+ if (argc > 1 && !(argv[1][0] == '-' && argv[1][1] == '\0')) {
+ fd = open(file = argv[1], O_RDONLY);
+ if (fd < 0) {
+ perror(argv[1]);
+ return 2;
+ }
+ }
+
+ rv = identify_fs(fd, &fstype, &bytes, 0);
+ if (rv == -1) {
+ perror(file);
+ return 2;
+ }
+
+ fstype = fstype ? fstype : "unknown";
+
+ fprintf(stdout, "FSTYPE=%s\nFSSIZE=%llu\n", fstype, bytes);
+ return rv;
+}
diff --git a/usr/kinit/fstype/minix_fs.h b/usr/kinit/fstype/minix_fs.h
new file mode 100644
index 0000000..e2899f0
--- /dev/null
+++ b/usr/kinit/fstype/minix_fs.h
@@ -0,0 +1,85 @@
+#ifndef _LINUX_MINIX_FS_H
+#define _LINUX_MINIX_FS_H
+
+/*
+ * The minix filesystem constants/structures
+ */
+
+/*
+ * Thanks to Kees J Bot for sending me the definitions of the new
+ * minix filesystem (aka V2) with bigger inodes and 32-bit block
+ * pointers.
+ */
+
+#define MINIX_ROOT_INO 1
+
+/* Not the same as the bogus LINK_MAX in <linux/limits.h>. Oh well. */
+#define MINIX_LINK_MAX 250
+#define MINIX2_LINK_MAX 65530
+
+#define MINIX_I_MAP_SLOTS 8
+#define MINIX_Z_MAP_SLOTS 64
+#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
+#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
+#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
+#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
+#define MINIX_VALID_FS 0x0001 /* Clean fs. */
+#define MINIX_ERROR_FS 0x0002 /* fs has errors. */
+
+#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
+#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
+
+/*
+ * This is the original minix inode layout on disk.
+ * Note the 8-bit gid and atime and ctime.
+ */
+struct minix_inode {
+ __u16 i_mode;
+ __u16 i_uid;
+ __u32 i_size;
+ __u32 i_time;
+ __u8 i_gid;
+ __u8 i_nlinks;
+ __u16 i_zone[9];
+};
+
+/*
+ * The new minix inode has all the time entries, as well as
+ * long block numbers and a third indirect block (7+1+1+1
+ * instead of 7+1+1). Also, some previously 8-bit values are
+ * now 16-bit. The inode is now 64 bytes instead of 32.
+ */
+struct minix2_inode {
+ __u16 i_mode;
+ __u16 i_nlinks;
+ __u16 i_uid;
+ __u16 i_gid;
+ __u32 i_size;
+ __u32 i_atime;
+ __u32 i_mtime;
+ __u32 i_ctime;
+ __u32 i_zone[10];
+};
+
+/*
+ * minix super-block data on disk
+ */
+struct minix_super_block {
+ __u16 s_ninodes;
+ __u16 s_nzones;
+ __u16 s_imap_blocks;
+ __u16 s_zmap_blocks;
+ __u16 s_firstdatazone;
+ __u16 s_log_zone_size;
+ __u32 s_max_size;
+ __u16 s_magic;
+ __u16 s_state;
+ __u32 s_zones;
+};
+
+struct minix_dir_entry {
+ __u16 inode;
+ char name[0];
+};
+
+#endif
diff --git a/usr/kinit/fstype/nilfs_fs.h b/usr/kinit/fstype/nilfs_fs.h
new file mode 100644
index 0000000..0845edf
--- /dev/null
+++ b/usr/kinit/fstype/nilfs_fs.h
@@ -0,0 +1,64 @@
+#ifndef __NILFS_FS_H
+#define __NILFS_FS_H
+
+#define NILFS_SUPER_MAGIC 0x3434 /* NILFS filesystem magic number */
+
+/*
+ * struct nilfs_super_block - structure of super block on disk
+ */
+struct nilfs_super_block {
+ __le32 s_rev_level; /* Revision level */
+ __le16 s_minor_rev_level; /* minor revision level */
+ __le16 s_magic; /* Magic signature */
+
+ __le16 s_bytes; /* Bytes count of CRC calculation
+ for this structure. s_reserved
+ is excluded. */
+ __le16 s_flags; /* flags */
+ __le32 s_crc_seed; /* Seed value of CRC calculation */
+ __le32 s_sum; /* Check sum of super block */
+
+ __le32 s_log_block_size; /* Block size represented as follows
+ blocksize = 1 << (s_log_block_size + 10) */
+ __le64 s_nsegments; /* Number of segments in filesystem */
+ __le64 s_dev_size; /* block device size in bytes */
+ __le64 s_first_data_block; /* 1st seg disk block number */
+ __le32 s_blocks_per_segment; /* number of blocks per full segment */
+ __le32 s_r_segments_percentage;/* Reserved segments percentage */ /* or __le16 */
+
+ __le64 s_last_cno; /* Last checkpoint number */
+ __le64 s_last_pseg; /* disk block addr pseg written last */
+ __le64 s_last_seq; /* seq. number of seg written last */
+ __le64 s_free_blocks_count; /* Free blocks count */
+
+ __le64 s_ctime; /* Creation time (execution time of newfs) */
+ __le64 s_mtime; /* Mount time */
+ __le64 s_wtime; /* Write time */
+ __le16 s_mnt_count; /* Mount count */
+ __le16 s_max_mnt_count; /* Maximal mount count */
+ __le16 s_state; /* File system state */
+ __le16 s_errors; /* Behaviour when detecting errors */
+ __le64 s_lastcheck; /* time of last check */
+
+ __le32 s_checkinterval; /* max. time between checks */
+ __le32 s_creator_os; /* OS */
+ __le16 s_def_resuid; /* Default uid for reserved blocks */
+ __le16 s_def_resgid; /* Default gid for reserved blocks */
+ __le32 s_first_ino; /* First non-reserved inode */ /* or __le16 */
+
+ __le16 s_inode_size; /* Size of an inode */
+ __le16 s_dat_entry_size; /* Size of a dat entry */
+ __le16 s_checkpoint_size; /* Size of a checkpoint */
+ __le16 s_segment_usage_size; /* Size of a segment usage */
+
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+
+ __le32 s_c_interval; /* Commit interval of segment */
+ __le32 s_c_block_max; /* Threshold of data amount for
+ the segment construction */
+ __u32 s_reserved[192]; /* padding to the end of the block */
+};
+
+#endif /* __NILFS_FS_H */
diff --git a/usr/kinit/fstype/ocfs2_fs.h b/usr/kinit/fstype/ocfs2_fs.h
new file mode 100644
index 0000000..b71cb61
--- /dev/null
+++ b/usr/kinit/fstype/ocfs2_fs.h
@@ -0,0 +1,90 @@
+#ifndef _OCFS2_FS_H
+#define _OCFS2_FS_H
+
+/* Object signatures */
+#define OCFS2_SUPER_BLOCK_SIGNATURE "OCFSV2"
+
+#define OCFS2_VOL_UUID_LEN 16
+#define OCFS2_MAX_VOL_LABEL_LEN 64
+
+/*
+ * On disk superblock for OCFS2
+ * Note that it is contained inside an ocfs2_dinode, so all offsets
+ * are relative to the start of ocfs2_dinode.id2.
+ */
+struct ocfs2_super_block {
+/*00*/ uint16_t s_major_rev_level;
+ uint16_t s_minor_rev_level;
+ uint16_t s_mnt_count;
+ int16_t s_max_mnt_count;
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint32_t s_checkinterval; /* Max time between checks */
+/*10*/ uint64_t s_lastcheck; /* Time of last check */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_feature_compat; /* Compatible feature set */
+/*20*/ uint32_t s_feature_incompat; /* Incompatible feature set */
+ uint32_t s_feature_ro_compat; /* Readonly-compatible feature set */
+ uint64_t s_root_blkno; /* Offset, in blocks, of root directory
+ dinode */
+/*30*/ uint64_t s_system_dir_blkno; /* Offset, in blocks, of system
+ directory dinode */
+ uint32_t s_blocksize_bits; /* Blocksize for this fs */
+ uint32_t s_clustersize_bits; /* Clustersize for this fs */
+/*40*/ uint16_t s_max_slots; /* Max number of simultaneous mounts
+ before tunefs required */
+ uint16_t s_reserved1;
+ uint32_t s_reserved2;
+ uint64_t s_first_cluster_group; /* Block offset of 1st cluster
+ * group header */
+/*50*/ uint8_t s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
+/*90*/ uint8_t s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */
+/*A0*/
+} __attribute__ ((packed));
+
+/*
+ * On disk inode for OCFS2
+ */
+struct ocfs2_dinode {
+/*00*/ uint8_t i_signature[8]; /* Signature for validation */
+ uint32_t i_generation; /* Generation number */
+ uint16_t i_suballoc_slot; /* Slot suballocator this inode
+ belongs to */
+ int16_t i_suballoc_bit; /* Bit offset in suballocator
+ block group */
+/*10*/ uint32_t i_reserved0;
+ uint32_t i_clusters; /* Cluster count */
+ uint32_t i_uid; /* Owner UID */
+ uint32_t i_gid; /* Owning GID */
+/*20*/ uint64_t i_size; /* Size in bytes */
+ uint16_t i_mode; /* File mode */
+ uint16_t i_links_count; /* Links count */
+ uint32_t i_flags; /* File flags */
+/*30*/ uint64_t i_atime; /* Access time */
+ uint64_t i_ctime; /* Creation time */
+/*40*/ uint64_t i_mtime; /* Modification time */
+ uint64_t i_dtime; /* Deletion time */
+/*50*/ uint64_t i_blkno; /* Offset on disk, in blocks */
+ uint64_t i_last_eb_blk; /* Pointer to last extent
+ block */
+/*60*/ uint32_t i_fs_generation; /* Generation per fs-instance */
+ uint32_t i_atime_nsec;
+ uint32_t i_ctime_nsec;
+ uint32_t i_mtime_nsec;
+ uint32_t i_attr;
+ uint16_t i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL
+ was set in i_flags */
+ uint16_t i_reserved1;
+/*70*/ uint64_t i_reserved2[8];
+/*B8*/ uint64_t i_pad1;
+ uint64_t i_rdev; /* Device number */
+ uint32_t i_used; /* Bits (ie, clusters) used */
+ uint32_t i_total; /* Total bits (clusters)
+ available */
+ uint32_t ij_flags; /* Mounted, version, etc. */
+ uint32_t ij_pad;
+/*C0*/ struct ocfs2_super_block i_super;
+/* Actual on-disk size is one block */
+} __attribute__ ((packed));
+
+#endif /* _OCFS2_FS_H */
diff --git a/usr/kinit/fstype/reiser4_fs.h b/usr/kinit/fstype/reiser4_fs.h
new file mode 100644
index 0000000..af6ccc4
--- /dev/null
+++ b/usr/kinit/fstype/reiser4_fs.h
@@ -0,0 +1,31 @@
+#ifndef __REISER4_FS_H
+#define __REISER4_FS_H
+
+#define SS_MAGIC_SIZE 16
+
+/* reiser4 filesystem structure
+ *
+ * Master super block structure. It is the same for all reiser4 filesystems,
+ * so, we can declare it here. It contains common for all format fields like
+ * block size etc.
+ */
+struct reiser4_master_sb {
+ /* Master super block magic. */
+ char ms_magic[SS_MAGIC_SIZE];
+
+ /* Disk format in use. */
+ __u16 ms_format;
+
+ /* Filesyetem block size in use. */
+ __u16 ms_blksize;
+
+ /* Filesyetm uuid in use. */
+ char ms_uuid[SS_MAGIC_SIZE];
+
+ /* Filesystem label in use. */
+ char ms_label[SS_MAGIC_SIZE];
+} __attribute__ ((packed));
+
+#define REISER4_SUPER_MAGIC_STRING "ReIsEr4"
+
+#endif /* __REISER4_FS_H */
diff --git a/usr/kinit/fstype/reiserfs_fs.h b/usr/kinit/fstype/reiserfs_fs.h
new file mode 100644
index 0000000..096d505
--- /dev/null
+++ b/usr/kinit/fstype/reiserfs_fs.h
@@ -0,0 +1,74 @@
+#ifndef __REISERFS_FS_H
+#define __REISERFS_FS_H
+
+struct journal_params {
+ __u32 jp_journal_1st_block; /* where does journal start from on its
+ * device */
+ __u32 jp_journal_dev; /* journal device st_rdev */
+ __u32 jp_journal_size; /* size of the journal */
+ __u32 jp_journal_trans_max; /* max number of blocks in a transaction. */
+ __u32 jp_journal_magic; /* random value made on fs creation (this
+ * was sb_journal_block_count) */
+ __u32 jp_journal_max_batch; /* max number of blocks to batch into a
+ * trans */
+ __u32 jp_journal_max_commit_age; /* in seconds, how old can an async
+ * commit be */
+ __u32 jp_journal_max_trans_age; /* in seconds, how old can a transaction
+ * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+ __u32 s_block_count; /* blocks count */
+ __u32 s_free_blocks; /* free blocks count */
+ __u32 s_root_block; /* root block number */
+ struct journal_params s_journal;
+ __u16 s_blocksize; /* block size */
+ __u16 s_oid_maxsize; /* max size of object id array, see
+ * get_objectid() commentary */
+ __u16 s_oid_cursize; /* current size of object id array */
+ __u16 s_umount_state; /* this is set to 1 when filesystem was
+ * umounted, to 2 - when not */
+ char s_magic[10]; /* reiserfs magic string indicates that
+ * file system is reiserfs:
+ * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+ __u16 s_fs_state; /* it is set to used by fsck to mark which
+ * phase of rebuilding is done */
+ __u32 s_hash_function_code; /* indicate, what hash function is being use
+ * to sort names in a directory*/
+ __u16 s_tree_height; /* height of disk tree */
+ __u16 s_bmap_nr; /* amount of bitmap blocks needed to address
+ * each block of file system */
+ __u16 s_version; /* this field is only reliable on filesystem
+ * with non-standard journal */
+ __u16 s_reserved_for_journal; /* size in blocks of journal area on main
+ * device, we need to keep after
+ * making fs with non-standard journal */
+} __attribute__ ((__packed__));
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+ struct reiserfs_super_block_v1 s_v1;
+ __u32 s_inode_generation;
+ __u32 s_flags; /* Right now used only by inode-attributes, if enabled */
+ unsigned char s_uuid[16]; /* filesystem unique identifier */
+ unsigned char s_label[16]; /* filesystem volume label */
+ char s_unused[88]; /* zero filled by mkreiserfs and
+ * reiserfs_convert_objectid_map_v1()
+ * so any additions must be updated
+ * there as well. */
+} __attribute__ ((__packed__));
+
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+#define SB_V1_DISK_SUPER_BLOCK(s) (&((s)->s_v1))
+#define REISERFS_BLOCKSIZE(s) \
+ __le32_to_cpu((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define REISERFS_BLOCK_COUNT(s) \
+ __le32_to_cpu((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define REISERFS_MAGIC(s) \
+ (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+
+#endif /* __REISERFS_FS_H */
diff --git a/usr/kinit/fstype/romfs_fs.h b/usr/kinit/fstype/romfs_fs.h
new file mode 100644
index 0000000..c490fbc
--- /dev/null
+++ b/usr/kinit/fstype/romfs_fs.h
@@ -0,0 +1,56 @@
+#ifndef __LINUX_ROMFS_FS_H
+#define __LINUX_ROMFS_FS_H
+
+/* The basic structures of the romfs filesystem */
+
+#define ROMBSIZE BLOCK_SIZE
+#define ROMBSBITS BLOCK_SIZE_BITS
+#define ROMBMASK (ROMBSIZE-1)
+#define ROMFS_MAGIC 0x7275
+
+#define ROMFS_MAXFN 128
+
+#define __mkw(h,l) (((h)&0x00ff)<< 8|((l)&0x00ff))
+#define __mkl(h,l) (((h)&0xffff)<<16|((l)&0xffff))
+#define __mk4(a,b,c,d) cpu_to_be32(__mkl(__mkw(a,b),__mkw(c,d)))
+#define ROMSB_WORD0 __mk4('-','r','o','m')
+#define ROMSB_WORD1 __mk4('1','f','s','-')
+
+/* On-disk "super block" */
+
+struct romfs_super_block {
+ __be32 word0;
+ __be32 word1;
+ __be32 size;
+ __be32 checksum;
+ char name[0]; /* volume name */
+};
+
+/* On disk inode */
+
+struct romfs_inode {
+ __be32 next; /* low 4 bits see ROMFH_ */
+ __be32 spec;
+ __be32 size;
+ __be32 checksum;
+ char name[0];
+};
+
+#define ROMFH_TYPE 7
+#define ROMFH_HRD 0
+#define ROMFH_DIR 1
+#define ROMFH_REG 2
+#define ROMFH_SYM 3
+#define ROMFH_BLK 4
+#define ROMFH_CHR 5
+#define ROMFH_SCK 6
+#define ROMFH_FIF 7
+#define ROMFH_EXEC 8
+
+/* Alignment */
+
+#define ROMFH_SIZE 16
+#define ROMFH_PAD (ROMFH_SIZE-1)
+#define ROMFH_MASK (~ROMFH_PAD)
+
+#endif
diff --git a/usr/kinit/fstype/squashfs_fs.h b/usr/kinit/fstype/squashfs_fs.h
new file mode 100644
index 0000000..c18365d
--- /dev/null
+++ b/usr/kinit/fstype/squashfs_fs.h
@@ -0,0 +1,48 @@
+#ifndef __SQUASHFS_FS_H
+#define __SQUASHFS_FS_H
+
+/*
+ * Squashfs
+ */
+
+#define SQUASHFS_MAGIC 0x73717368
+#define SQUASHFS_MAGIC_SWAP 0x68737173
+
+/*
+ * Squashfs + LZMA
+ */
+
+#define SQUASHFS_MAGIC_LZMA 0x71736873
+#define SQUASHFS_MAGIC_LZMA_SWAP 0x73687371
+
+/* definitions for structures on disk */
+struct squashfs_super_block {
+ unsigned int s_magic;
+ unsigned int inodes;
+ unsigned int bytes_used_2;
+ unsigned int uid_start_2;
+ unsigned int guid_start_2;
+ unsigned int inode_table_start_2;
+ unsigned int directory_table_start_2;
+ unsigned int s_major:16;
+ unsigned int s_minor:16;
+ unsigned int block_size_1:16;
+ unsigned int block_log:16;
+ unsigned int flags:8;
+ unsigned int no_uids:8;
+ unsigned int no_guids:8;
+ unsigned int mkfs_time /* time of filesystem creation */;
+ long long root_inode;
+ unsigned int block_size;
+ unsigned int fragments;
+ unsigned int fragment_table_start_2;
+ long long bytes_used;
+ long long uid_start;
+ long long guid_start;
+ long long inode_table_start;
+ long long directory_table_start;
+ long long fragment_table_start;
+ long long lookup_table_start;
+} __attribute__ ((packed));
+
+#endif /* __SQUASHFS_FS_H */
diff --git a/usr/kinit/fstype/swap_fs.h b/usr/kinit/fstype/swap_fs.h
new file mode 100644
index 0000000..7b7fddb
--- /dev/null
+++ b/usr/kinit/fstype/swap_fs.h
@@ -0,0 +1,25 @@
+#ifndef __LINUX_SWAP_FS_H
+#define __LINUX_SWAP_FS_H
+
+/* The basic structures of the swap super block */
+#define SWAP_MAGIC_L 10
+#define SWAP_RESERVED_L (1024 - SWAP_MAGIC_L)
+#define SWAP_MAGIC_1 "SWAP-SPACE"
+#define SWAP_MAGIC_2 "SWAPSPACE2"
+
+/* Suspend signatures, located at same addr as swap magic */
+#define SUSP_MAGIC_L 9
+#define SUSP_MAGIC_1 "S1SUSPEND"
+#define SUSP_MAGIC_2 "S2SUSPEND"
+#define SUSP_MAGIC_U "ULSUSPEND"
+
+/* The superblock is the last block in the first page */
+#define SWAP_OFFSET() ((getpagesize() - 1024) >> 10)
+
+/* On-disk "super block" */
+struct swap_super_block {
+ char reserved[SWAP_RESERVED_L];
+ char magic[SWAP_MAGIC_L];
+};
+
+#endif
diff --git a/usr/kinit/fstype/xfs_sb.h b/usr/kinit/fstype/xfs_sb.h
new file mode 100644
index 0000000..fd54bc4
--- /dev/null
+++ b/usr/kinit/fstype/xfs_sb.h
@@ -0,0 +1,21 @@
+#ifndef __XFS_SB_H
+#define __XFS_SB_H
+
+/*
+ * Super block
+ * Fits into a sector-sized buffer at address 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */
+
+typedef struct xfs_sb {
+ __u32 sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ __u32 sb_blocksize; /* logical block size, bytes */
+ __u64 sb_dblocks; /* number of data blocks */
+} xfs_sb_t;
+
+#endif /* __XFS_SB_H */
diff --git a/usr/kinit/getarg.c b/usr/kinit/getarg.c
new file mode 100644
index 0000000..fcce247
--- /dev/null
+++ b/usr/kinit/getarg.c
@@ -0,0 +1,57 @@
+#include <string.h>
+#include "kinit.h"
+
+/*
+ * Routines that hunt for a specific argument. Please note that
+ * they actually search the array backwards. That is because on the
+ * kernel command lines, it's legal to override an earlier argument
+ * with a later argument.
+ */
+
+/*
+ * Was this boolean argument passed? If so return the index in the
+ * argv array for it. For conflicting boolean options, use the
+ * one with the higher index. The only case when the return value
+ * can be equal, is when they're both zero; so equality can be used
+ * as the default option choice.
+ *
+ * In other words, if two options "a" and "b" are opposites, and "a"
+ * is the default, this can be coded as:
+ *
+ * if (get_flag(argc,argv,"a") >= get_flag(argc,argv,"b"))
+ * do_a_stuff();
+ * else
+ * do_b_stuff();
+ */
+int get_flag(int argc, char *argv[], const char *name)
+{
+ int i;
+
+ for (i = argc-1; i > 0; i--) {
+ if (!strcmp(argv[i], name))
+ return i;
+ }
+ return 0;
+}
+
+/*
+ * Was this textual parameter (foo=option) passed?
+ *
+ * This returns the latest instance of such an option in the argv array.
+ */
+char *get_arg(int argc, char *argv[], const char *name)
+{
+ int len = strlen(name);
+ char *ret = NULL;
+ int i;
+
+ for (i = argc-1; i > 0; i--) {
+ if (argv[i] && strncmp(argv[i], name, len) == 0 &&
+ (argv[i][len] != '\0')) {
+ ret = argv[i] + len;
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/usr/kinit/getintfile.c b/usr/kinit/getintfile.c
new file mode 100644
index 0000000..41ba475
--- /dev/null
+++ b/usr/kinit/getintfile.c
@@ -0,0 +1,30 @@
+/*
+ * Open a file and read it, assuming it contains a single long value.
+ * Return 0 if we read a valid value, otherwise -1.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "kinit.h"
+
+int getintfile(const char *path, long *val)
+{
+ char buffer[64];
+ char *ep;
+ FILE *f;
+
+ f = fopen(path, "r");
+ if (!f)
+ return -1;
+
+ ep = buffer + fread(buffer, 1, sizeof buffer - 1, f);
+ fclose(f);
+ *ep = '\0';
+
+ *val = strtol(buffer, &ep, 0);
+ if (*ep && *ep != '\n')
+ return -1;
+ else
+ return 0;
+}
diff --git a/usr/kinit/initrd.c b/usr/kinit/initrd.c
new file mode 100644
index 0000000..5833f2f
--- /dev/null
+++ b/usr/kinit/initrd.c
@@ -0,0 +1,204 @@
+/*
+ * Handle initrd, thus putting the backwards into backwards compatible
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include "do_mounts.h"
+#include "kinit.h"
+#include "xpio.h"
+
+#define BUF_SIZE 65536 /* Should be a power of 2 */
+
+/*
+ * Copy the initrd to /dev/ram0, copy from the end to the beginning
+ * to avoid taking 2x the memory.
+ */
+static int rd_copy_uncompressed(int ffd, int dfd)
+{
+ char buffer[BUF_SIZE];
+ off_t bytes;
+ struct stat st;
+
+ dprintf("kinit: uncompressed initrd\n");
+
+ if (ffd < 0 || fstat(ffd, &st) || !S_ISREG(st.st_mode) ||
+ (bytes = st.st_size) == 0)
+ return -1;
+
+ while (bytes) {
+ ssize_t blocksize = ((bytes - 1) & (BUF_SIZE - 1)) + 1;
+ off_t offset = bytes - blocksize;
+
+ dprintf("kinit: copying %zd bytes at offset %llu\n",
+ blocksize, offset);
+
+ if (xpread(ffd, buffer, blocksize, offset) != blocksize ||
+ xpwrite(dfd, buffer, blocksize, offset) != blocksize)
+ return -1;
+
+ ftruncate(ffd, offset); /* Free up memory */
+ bytes = offset;
+ }
+ return 0;
+}
+
+static int rd_copy_image(const char *path)
+{
+ int ffd = open(path, O_RDONLY);
+ int rv = -1;
+ unsigned char gzip_magic[2];
+
+ if (ffd < 0)
+ goto barf;
+
+ if (xpread(ffd, gzip_magic, 2, 0) == 2 &&
+ gzip_magic[0] == 037 && gzip_magic[1] == 0213) {
+ FILE *wfd = fopen("/dev/ram0", "w");
+ if (!wfd)
+ goto barf;
+ rv = load_ramdisk_compressed(path, wfd, 0);
+ fclose(wfd);
+ } else {
+ int dfd = open("/dev/ram0", O_WRONLY);
+ if (dfd < 0)
+ goto barf;
+ rv = rd_copy_uncompressed(ffd, dfd);
+ close(dfd);
+ }
+
+barf:
+ if (ffd >= 0)
+ close(ffd);
+ return rv;
+}
+
+/*
+ * Run /linuxrc, for emulation of old-style initrd
+ */
+static int run_linuxrc(int argc, char *argv[], dev_t root_dev)
+{
+ int root_fd, old_fd;
+ pid_t pid;
+ long realroot = Root_RAM0;
+ const char *ramdisk_name = "/dev/ram0";
+ FILE *fp;
+
+ dprintf("kinit: mounting initrd\n");
+ mkdir("/root", 0700);
+ if (!mount_block(ramdisk_name, "/root", NULL, MS_VERBOSE, NULL))
+ return -errno;
+
+ /* Write the current "real root device" out to procfs */
+ dprintf("kinit: real_root_dev = %#x\n", root_dev);
+ fp = fopen("/proc/sys/kernel/real-root-dev", "w");
+ fprintf(fp, "%u", root_dev);
+ fclose(fp);
+
+ mkdir("/old", 0700);
+ root_fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
+ old_fd = open("/old", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
+
+ if (root_fd < 0 || old_fd < 0)
+ return -errno;
+
+ if (chdir("/root") ||
+ mount(".", "/", NULL, MS_MOVE, NULL) || chroot("."))
+ return -errno;
+
+ pid = vfork();
+ if (pid == 0) {
+ setsid();
+ /* Looks like linuxrc doesn't get the init environment
+ or parameters. Weird, but so is the whole linuxrc bit. */
+ execl("/linuxrc", "linuxrc", NULL);
+ _exit(255);
+ } else if (pid > 0) {
+ dprintf("kinit: Waiting for linuxrc to complete...\n");
+ while (waitpid(pid, NULL, 0) != pid)
+ ;
+ dprintf("kinit: linuxrc done\n");
+ } else {
+ return -errno;
+ }
+
+ if (fchdir(old_fd) ||
+ mount("/", ".", NULL, MS_MOVE, NULL) ||
+ fchdir(root_fd) || chroot("."))
+ return -errno;
+
+ close(root_fd);
+ close(old_fd);
+
+ getintfile("/proc/sys/kernel/real-root-dev", &realroot);
+
+ /* If realroot is Root_RAM0, then the initrd did any necessary work */
+ if (realroot == Root_RAM0) {
+ if (mount("/old", "/root", NULL, MS_MOVE, NULL))
+ return -errno;
+ } else {
+ mount_root(argc, argv, (dev_t) realroot, NULL);
+
+ /* If /root/initrd exists, move the initrd there, otherwise discard */
+ if (!mount("/old", "/root/initrd", NULL, MS_MOVE, NULL)) {
+ /* We're good */
+ } else {
+ int olddev = open(ramdisk_name, O_RDWR);
+ umount2("/old", MNT_DETACH);
+ if (olddev < 0 ||
+ ioctl(olddev, BLKFLSBUF, 0) ||
+ close(olddev)) {
+ fprintf(stderr,
+ "%s: Cannot flush initrd contents\n",
+ progname);
+ }
+ }
+ }
+
+ rmdir("/old");
+ return 0;
+}
+
+int initrd_load(int argc, char *argv[], dev_t root_dev)
+{
+ if (access("/initrd.image", R_OK))
+ return 0; /* No initrd */
+
+ dprintf("kinit: initrd found\n");
+
+ create_dev("/dev/ram0", Root_RAM0);
+
+ if (rd_copy_image("/initrd.image") || unlink("/initrd.image")) {
+ fprintf(stderr, "%s: initrd installation failed (too big?)\n",
+ progname);
+ return 0; /* Failed to copy initrd */
+ }
+
+ dprintf("kinit: initrd copied\n");
+
+ if (root_dev == Root_MULTI) {
+ dprintf("kinit: skipping linuxrc: incompatible with multiple roots\n");
+ /* Mounting initrd as ordinary root */
+ return 0;
+ }
+
+ if (root_dev != Root_RAM0) {
+ int err;
+ dprintf("kinit: running linuxrc\n");
+ err = run_linuxrc(argc, argv, root_dev);
+ if (err)
+ fprintf(stderr, "%s: running linuxrc: %s\n", progname,
+ strerror(-err));
+ return 1; /* initrd is root, or run_linuxrc took care of it */
+ } else {
+ dprintf("kinit: permament (or pivoting) initrd, not running linuxrc\n");
+ return 0; /* Mounting initrd as ordinary root */
+ }
+}
diff --git a/usr/kinit/ipconfig/Kbuild b/usr/kinit/ipconfig/Kbuild
new file mode 100644
index 0000000..686b03b
--- /dev/null
+++ b/usr/kinit/ipconfig/Kbuild
@@ -0,0 +1,35 @@
+#
+# Kbuild file for ipconfig
+#
+
+static-y := static/ipconfig
+shared-y := shared/ipconfig
+
+# common .o files
+objs := main.o netdev.o packet.o
+# dhcp
+objs += dhcp_proto.o
+# bootp
+objs += bootp_proto.o
+
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/ipconfig-y := $(objs)
+shared/ipconfig-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
diff --git a/usr/kinit/ipconfig/README.ipconfig b/usr/kinit/ipconfig/README.ipconfig
new file mode 100644
index 0000000..5ee87e5
--- /dev/null
+++ b/usr/kinit/ipconfig/README.ipconfig
@@ -0,0 +1,120 @@
+BOOTP/DHCP client for klibc
+---------------------------
+
+Usage:
+
+ipconfig [-c proto] [-d interface] [-i identifier]
+ [-n] [-p port] [-t timeout] [interface ...]
+
+-c proto Use PROTO as the configuration protocol for all
+ interfaces, unless overridden by specific interfaces.
+-d interface Either the name of an interface, or a long spec.
+-i identifier DHCP vendor class identifier. The default is
+ "Linux ipconfig".
+-n Do nothing - just print the configuration that would
+ be performed.
+-p port Send bootp/dhcp broadcasts from PORT, to PORT - 1.
+-t timeout Give up on all unconfigured interfaces after TIMEOUT secs.
+
+You can configure multiple interfaces by passing multiple interface
+specs on the command line, or by using the special interface name
+"all". If you're autoconfiguring any interfaces, ipconfig will wait
+until either all such interfaces have been configured, or the timeout
+passes.
+
+PROTO can be one of the following, which selects the autoconfiguration
+protocol to use:
+
+not specified use all protocols (the default)
+dhcp use bootp and dhcp
+bootp use bootp only
+rarp use rarp (not currently supported)
+none no autoconfiguration - either static config, or none at all
+
+An interface spec can be either short form, which is just the name of
+an interface (eth0 or whatever), or long form. The long form consists
+of two or more fields, separated by colons:
+
+<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:
+ <dns0-ip>:<dns1-ip>:<ntp0-ip>:...
+
+ <client-ip> IP address of the client. If empty, the address will
+ either be determined by RARP/BOOTP/DHCP. What protocol
+ is used de- pends on the <autoconf> parameter. If this
+ parameter is not empty, autoconf will be used.
+
+ <server-ip> IP address of the NFS server. If RARP is used to
+ determine the client address and this parameter is NOT
+ empty only replies from the specified server are
+ accepted. To use different RARP and NFS server,
+ specify your RARP server here (or leave it blank), and
+ specify your NFS server in the `nfsroot' parameter
+ (see above). If this entry is blank the address of the
+ server is used which answered the RARP/BOOTP/DHCP
+ request.
+
+ <gw-ip> IP address of a gateway if the server is on a different
+ subnet. If this entry is empty no gateway is used and the
+ server is assumed to be on the local network, unless a
+ value has been received by BOOTP/DHCP.
+
+ <netmask> Netmask for local network interface. If this is empty,
+ the netmask is derived from the client IP address assuming
+ classful addressing, unless overridden in BOOTP/DHCP reply.
+
+ <hostname> Name of the client. If empty, the client IP address is
+ used in ASCII notation, or the value received by
+ BOOTP/DHCP.
+
+ <device> Name of network device to use. If this is empty, all
+ devices are used for RARP/BOOTP/DHCP requests, and the
+ first one we receive a reply on is configured. If you
+ have only one device, you can safely leave this blank.
+
+ <autoconf> Method to use for autoconfiguration. If this is either
+ 'rarp', 'bootp', or 'dhcp' the specified protocol is
+ used. If the value is 'both', 'all' or empty, all
+ protocols are used. 'off', 'static' or 'none' means
+ no autoconfiguration.
+
+ <dns0-ip> IP address of primary nameserver.
+
+ Default: None if not using autoconfiguration; determined
+ automatically if using autoconfiguration.
+
+ <dns1-ip> IP address of secondary nameserver.
+ See <dns0-ip>.
+
+ <ntp0-ip> IP address of a Network Time Protocol (NTP) server.
+ Currently ignored.
+
+ ... Additional fields will be ignored.
+
+IP addresses and netmasks must be either absent (defaulting to zero)
+or presented in dotted-quad notation.
+
+An interface spec can be prefixed with either "ip=", "nfsaddrs=", both
+of which are ignored. These (along with the ugliness of the long
+form) are present for compatibility with the in-kernel ipconfig code
+from 2.4 and earlier kernels.
+
+Here are a few examples of valid ipconfig command lines.
+
+Enable the loopback interface:
+ ipconfig 127.0.0.1:::::lo:none
+
+Try to configure eth0 using bootp for up to 30 seconds:
+ ipconfig -t 30 -c bootp eth0
+
+Configure eth0 and eth1 using dhcp or bootp, and eth2 statically:
+ ipconfig -c any eth0 eth1 192.168.1.1:::::eth2:none
+
+--
+
+From Russell's original README, and still true:
+
+The code in main.c is yucky imho. Needs cleaning.
+
+--
+Russell King (2002/10/22)
+Bryan O'Sullivan (2003/04/29)
diff --git a/usr/kinit/ipconfig/bootp_packet.h b/usr/kinit/ipconfig/bootp_packet.h
new file mode 100644
index 0000000..1d5bd0d
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_packet.h
@@ -0,0 +1,44 @@
+#ifndef BOOTP_PACKET_H
+#define BOOTP_PACKET_H
+
+#include <sys/uio.h>
+
+struct netdev;
+
+/* packet ops */
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY 2
+
+/* your basic bootp packet */
+struct bootp_hdr {
+ uint8_t op;
+ uint8_t htype;
+ uint8_t hlen;
+ uint8_t hops;
+ uint32_t xid;
+ uint16_t secs;
+ uint16_t flags;
+ uint32_t ciaddr;
+ uint32_t yiaddr;
+ uint32_t siaddr;
+ uint32_t giaddr;
+ uint8_t chaddr[16];
+ char server_name[64];
+ char boot_file[128];
+ /* 312 bytes of extensions */
+};
+
+/*
+ * memory size of BOOTP Vendor Extensions/DHCP Options for receiving
+ *
+ * generic_ether_mtu:1500, min_sizeof(ip_hdr):20, sizeof(udp_hdr):8
+ *
+ * #define BOOTP_EXTS_SIZE (1500 - 20 - 8 - sizeof(struct bootp_hdr))
+ */
+/* larger size for backward compatibility of ipconfig */
+#define BOOTP_EXTS_SIZE 1500
+
+/* minimum length of BOOTP/DHCP packet on sending */
+#define BOOTP_MIN_LEN 300
+
+#endif /* BOOTP_PACKET_H */
diff --git a/usr/kinit/ipconfig/bootp_proto.c b/usr/kinit/ipconfig/bootp_proto.c
new file mode 100644
index 0000000..f6f9dd4
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_proto.c
@@ -0,0 +1,565 @@
+/*
+ * BOOTP packet protocol handling.
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "packet.h"
+
+static uint8_t bootp_options[312] = {
+ [ 0] = 99, 130, 83, 99,/* RFC1048 magic cookie */
+ [ 4] = 1, 4, /* 4- 9 subnet mask */
+ [ 10] = 3, 4, /* 10- 15 default gateway */
+ [ 16] = 5, 8, /* 16- 25 nameserver */
+ [ 26] = 12, 32, /* 26- 59 host name */
+ [ 60] = 40, 32, /* 60- 95 nis domain name */
+ [ 96] = 17, 40, /* 96-137 boot path */
+ [138] = 57, 2, 1, 150, /* 138-141 extension buffer */
+ [142] = 255, /* end of list */
+};
+
+/*
+ * Send a plain bootp request packet with options
+ */
+int bootp_send_request(struct netdev *dev)
+{
+ struct bootp_hdr bootp;
+ struct iovec iov[] = {
+ /* [0] = ip + udp headers */
+ [1] = {&bootp, sizeof(bootp)},
+ [2] = {bootp_options, 312}
+ };
+
+ memset(&bootp, 0, sizeof(struct bootp_hdr));
+
+ bootp.op = BOOTP_REQUEST, bootp.htype = dev->hwtype;
+ bootp.hlen = dev->hwlen;
+ bootp.xid = dev->bootp.xid;
+ bootp.ciaddr = dev->ip_addr;
+ bootp.secs = htons(time(NULL) - dev->open_time);
+ memcpy(bootp.chaddr, dev->hwaddr, 16);
+
+ dprintf("-> bootp xid 0x%08x secs 0x%08x ",
+ bootp.xid, ntohs(bootp.secs));
+
+ return packet_send(dev, iov, 2);
+}
+
+/*
+ * DESCRIPTION
+ * bootp_ext119_decode() decodes Domain Search Option data.
+ * The decoded string is separated with ' '.
+ * For example, it is either "foo.bar.baz. bar.baz.", "foo.bar.", or "foo.".
+ *
+ * ARGUMENTS
+ * const uint8_t *ext
+ * *ext is a pointer to a DHCP Domain Search Option data. *ext does not
+ * include a tag(code) octet and a length octet in DHCP options.
+ * For example, if *ext is {3, 'f', 'o', 'o', 0}, this function returns
+ * a pointer to a "foo." string.
+ *
+ * int16_t ext_size
+ * ext_size is the memory size of *ext. For example,
+ * if *ext is {3, 'f', 'o', 'o', 0}, ext_size must be 5.
+ *
+ * uint8_t *tmp
+ * *tmp is a pointer to a temporary memory space for decoding.
+ * The memory size must be equal to or more than ext_size.
+ * 'memset(tmp, 0, sizeof(tmp));' is not required, but values in *tmp
+ * are changed in decoding process.
+ *
+ * RETURN VALUE
+ * if OK, a pointer to a decoded string malloc-ed
+ * else , NULL
+ *
+ * SEE ALSO RFC3397
+ */
+static char *bootp_ext119_decode(const void *ext, int16_t ext_size, void *tmp)
+{
+ uint8_t *u8ext;
+ int_fast32_t i;
+ int_fast32_t decoded_size;
+ int_fast8_t currentdomain_is_singledot;
+
+ /* only for validating *ext */
+ uint8_t *is_pointee;
+ int_fast32_t is_pointee_size;
+
+ /* only for structing a decoded string */
+ char *decoded_str;
+ int_fast32_t dst_i;
+
+ if (ext == NULL || ext_size <= 0 || tmp == NULL)
+ return NULL;
+
+ u8ext = (uint8_t *)ext;
+ is_pointee = tmp;
+ memset(is_pointee, 0, (size_t)ext_size);
+ is_pointee_size = 0;
+
+ /*
+ * validate the format of *ext and
+ * calculate the memory size for a decoded string
+ */
+ i = 0;
+ decoded_size = 0;
+ currentdomain_is_singledot = 1;
+ while (1) {
+ if (i >= ext_size)
+ return NULL;
+
+ if (u8ext[i] == 0) {
+ /* Zero-ending */
+ if (currentdomain_is_singledot)
+ decoded_size++; /* for '.' */
+ decoded_size++; /* for ' ' or '\0' */
+ currentdomain_is_singledot = 1;
+ i++;
+ if (i == ext_size)
+ break;
+ is_pointee_size = i;
+ } else if (u8ext[i] < 0x40) {
+ /* Label(sub-domain string) */
+ int j;
+
+ /* loosely validate characters for domain names */
+ if (i + u8ext[i] >= ext_size)
+ return NULL;
+ for (j = i + 1; j <= i + u8ext[i]; j++)
+ if (!(u8ext[j] == '-' ||
+ ('0' <= u8ext[j] && u8ext[j] <= '9') ||
+ ('A' <= u8ext[j] && u8ext[j] <= 'Z') ||
+ ('a' <= u8ext[j] && u8ext[j] <= 'z')))
+ return NULL;
+
+ is_pointee[i] = 1;
+ decoded_size += u8ext[i] + 1; /* for Label + '.' */
+ currentdomain_is_singledot = 0;
+ i += u8ext[i] + 1;
+ } else if (u8ext[i] < 0xc0)
+ return NULL;
+
+ else {
+ /* Compression-pointer (to a prior Label) */
+ int_fast32_t p;
+
+ if (i + 1 >= ext_size)
+ return NULL;
+
+ p = ((0x3f & u8ext[i]) << 8) + u8ext[i + 1];
+ if (!(p < is_pointee_size && is_pointee[p]))
+ return NULL;
+
+ while (1) {
+ /* u8ext[p] was validated */
+ if (u8ext[p] == 0) {
+ /* Zero-ending */
+ decoded_size++;
+ break;
+ } else if (u8ext[p] < 0x40) {
+ /* Label(sub-domain string) */
+ decoded_size += u8ext[p] + 1;
+ p += u8ext[p] + 1;
+ } else {
+ /* Compression-pointer */
+ p = ((0x3f & u8ext[p]) << 8)
+ + u8ext[p + 1];
+ }
+ }
+
+ currentdomain_is_singledot = 1;
+ i += 2;
+ if (i == ext_size)
+ break;
+ is_pointee_size = i;
+ }
+ }
+
+
+ /*
+ * construct a decoded string
+ */
+ decoded_str = malloc(decoded_size);
+ if (decoded_str == NULL)
+ return NULL;
+
+ i = 0;
+ dst_i = 0;
+ currentdomain_is_singledot = 1;
+ while (1) {
+ if (u8ext[i] == 0) {
+ /* Zero-ending */
+ if (currentdomain_is_singledot) {
+ if (dst_i != 0)
+ dst_i++;
+ decoded_str[dst_i] = '.';
+ }
+ dst_i++;
+ decoded_str[dst_i] = ' ';
+
+ currentdomain_is_singledot = 1;
+ i++;
+ if (i == ext_size)
+ break;
+ } else if (u8ext[i] < 0x40) {
+ /* Label(sub-domain string) */
+ if (dst_i != 0)
+ dst_i++;
+ memcpy(&decoded_str[dst_i], &u8ext[i + 1],
+ (size_t)u8ext[i]);
+ dst_i += u8ext[i];
+ decoded_str[dst_i] = '.';
+
+ currentdomain_is_singledot = 0;
+ i += u8ext[i] + 1;
+ } else {
+ /* Compression-pointer (to a prior Label) */
+ int_fast32_t p;
+
+ p = ((0x3f & u8ext[i]) << 8) + u8ext[i + 1];
+ while (1) {
+ if (u8ext[p] == 0) {
+ /* Zero-ending */
+ decoded_str[dst_i++] = '.';
+ decoded_str[dst_i] = ' ';
+ break;
+ } else if (u8ext[p] < 0x40) {
+ /* Label(sub-domain string) */
+ dst_i++;
+ memcpy(&decoded_str[dst_i],
+ &u8ext[p + 1],
+ (size_t)u8ext[p]);
+ dst_i += u8ext[p];
+ decoded_str[dst_i] = '.';
+
+ p += u8ext[p] + 1;
+ } else {
+ /* Compression-pointer */
+ p = ((0x3f & u8ext[p]) << 8)
+ + u8ext[p + 1];
+ }
+ }
+
+ currentdomain_is_singledot = 1;
+ i += 2;
+ if (i == ext_size)
+ break;
+ }
+ }
+ decoded_str[dst_i] = '\0';
+#ifdef DEBUG
+ if (dst_i + 1 != decoded_size) {
+ dprintf("bug:%s():bottom: malloc(%ld), write(%ld)\n",
+ __func__, (long)decoded_size, (long)(dst_i + 1));
+ exit(1);
+ }
+#endif
+ return decoded_str;
+}
+
+/*
+ * DESCRIPTION
+ * bootp_ext121_decode() decodes Classless Route Option data.
+ *
+ * ARGUMENTS
+ * const uint8_t *ext
+ * *ext is a pointer to a DHCP Classless Route Option data.
+ * For example, if *ext is {16, 192, 168, 192, 168, 42, 1},
+ * this function returns a pointer to
+ * {
+ * subnet = 192.168.0.0;
+ * netmask_width = 16;
+ * gateway = 192.168.42.1;
+ * next = NULL;
+ * }
+ *
+ * int16_t ext_size
+ * ext_size is the memory size of *ext. For example,
+ * if *ext is {16, 192, 168, 192, 168, 42, 1}, ext_size must be 7.
+ *
+ * RETURN VALUE
+ * if OK, a pointer to a decoded struct route malloc-ed
+ * else , NULL
+ *
+ * SEE ALSO RFC3442
+ */
+struct route *bootp_ext121_decode(const uint8_t *ext, int16_t ext_size)
+{
+ int16_t index = 0;
+ uint8_t netmask_width;
+ uint8_t significant_octets;
+ struct route *routes = NULL;
+ struct route *prev_route = NULL;
+
+ while (index < ext_size) {
+ netmask_width = ext[index];
+ index++;
+ if (netmask_width > 32) {
+ printf("IP-Config: Given Classless Route Option subnet mask width '%u' "
+ "exceeds IPv4 limit of 32. Ignoring remaining option.\n",
+ netmask_width);
+ return routes;
+ }
+ significant_octets = netmask_width / 8 + (netmask_width % 8 > 0);
+ if (ext_size - index < significant_octets + 4) {
+ printf("IP-Config: Given Classless Route Option remaining lengths (%u octets) "
+ "is shorter than the expected %u octets. Ignoring remaining options.\n",
+ ext_size - index, significant_octets + 4);
+ return routes;
+ }
+
+ struct route *route = malloc(sizeof(struct route));
+ if (route == NULL)
+ return routes;
+
+ /* convert only significant octets from byte array into integer in network byte order */
+ route->subnet = 0;
+ memcpy(&route->subnet, &ext[index], significant_octets);
+ index += significant_octets;
+ /* RFC3442 demands: After deriving a subnet number and subnet mask from
+ each destination descriptor, the DHCP client MUST zero any bits in
+ the subnet number where the corresponding bit in the mask is zero. */
+ route->subnet &= netdev_genmask(netmask_width);
+
+ /* convert octet array into network byte order */
+ memcpy(&route->gateway, &ext[index], 4);
+ index += 4;
+
+ route->netmask_width = netmask_width;
+ route->next = NULL;
+
+ if (prev_route == NULL) {
+ routes = route;
+ } else {
+ prev_route->next = route;
+ }
+ prev_route = route;
+ }
+ return routes;
+}
+
+/*
+ * Parse a bootp reply packet
+ */
+int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr,
+ uint8_t *exts, int extlen)
+{
+ uint8_t ext119_buf[BOOTP_EXTS_SIZE];
+ int16_t ext119_len = 0;
+ uint8_t ext121_buf[BOOTP_EXTS_SIZE];
+ int16_t ext121_len = 0;
+
+ dev->bootp.gateway = hdr->giaddr;
+ dev->ip_addr = hdr->yiaddr;
+ dev->ip_server = hdr->siaddr;
+ dev->ip_netmask = INADDR_ANY;
+ dev->ip_broadcast = INADDR_ANY;
+ dev->ip_gateway = hdr->giaddr;
+ dev->ip_nameserver[0] = INADDR_ANY;
+ dev->ip_nameserver[1] = INADDR_ANY;
+ dev->hostname[0] = '\0';
+ dev->nisdomainname[0] = '\0';
+ dev->bootpath[0] = '\0';
+ memcpy(&dev->filename, &hdr->boot_file, FNLEN);
+
+ if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
+ exts[2] == 83 && exts[3] == 99) {
+ uint8_t *ext;
+
+ for (ext = exts + 4; ext - exts < extlen;) {
+ int len;
+ uint8_t opt = *ext++;
+
+ if (opt == 0)
+ continue;
+ else if (opt == 255)
+ break;
+
+ if (ext - exts >= extlen)
+ break;
+ len = *ext++;
+
+ if (ext - exts + len > extlen)
+ break;
+ switch (opt) {
+ case 1: /* subnet mask */
+ if (len == 4)
+ memcpy(&dev->ip_netmask, ext, 4);
+ break;
+ case 3: /* default gateway */
+ if (len >= 4)
+ memcpy(&dev->ip_gateway, ext, 4);
+ break;
+ case 6: /* DNS server */
+ if (len >= 4)
+ memcpy(&dev->ip_nameserver, ext,
+ len >= 8 ? 8 : 4);
+ break;
+ case 12: /* host name */
+ if (len > sizeof(dev->hostname) - 1)
+ len = sizeof(dev->hostname) - 1;
+ memcpy(&dev->hostname, ext, len);
+ dev->hostname[len] = '\0';
+ break;
+ case 15: /* domain name */
+ if (len > sizeof(dev->dnsdomainname) - 1)
+ len = sizeof(dev->dnsdomainname) - 1;
+ memcpy(&dev->dnsdomainname, ext, len);
+ dev->dnsdomainname[len] = '\0';
+ break;
+ case 17: /* root path */
+ if (len > sizeof(dev->bootpath) - 1)
+ len = sizeof(dev->bootpath) - 1;
+ memcpy(&dev->bootpath, ext, len);
+ dev->bootpath[len] = '\0';
+ break;
+ case 26: /* interface MTU */
+ if (len == 2)
+ dev->mtu = (ext[0] << 8) + ext[1];
+ break;
+ case 28: /* broadcast addr */
+ if (len == 4)
+ memcpy(&dev->ip_broadcast, ext, 4);
+ break;
+ case 40: /* NIS domain name */
+ if (len > sizeof(dev->nisdomainname) - 1)
+ len = sizeof(dev->nisdomainname) - 1;
+ memcpy(&dev->nisdomainname, ext, len);
+ dev->nisdomainname[len] = '\0';
+ break;
+ case 54: /* server identifier */
+ if (len == 4 && !dev->ip_server)
+ memcpy(&dev->ip_server, ext, 4);
+ break;
+ case 119: /* Domain Search Option */
+ if (ext119_len >= 0 &&
+ ext119_len + len <= sizeof(ext119_buf)) {
+ memcpy(ext119_buf + ext119_len,
+ ext, len);
+ ext119_len += len;
+ } else
+ ext119_len = -1;
+
+ break;
+ case 121: /* Classless Static Route Option (RFC3442) */
+ if (ext121_len >= 0 &&
+ ext121_len + len <= sizeof(ext121_buf)) {
+ memcpy(ext121_buf + ext121_len,
+ ext, len);
+ ext121_len += len;
+ } else
+ ext121_len = -1;
+
+ break;
+ }
+
+ ext += len;
+ }
+ }
+ if (ext119_len > 0) {
+ char *ret;
+ uint8_t ext119_tmp[BOOTP_EXTS_SIZE];
+
+ ret = bootp_ext119_decode(ext119_buf, ext119_len, ext119_tmp);
+ if (ret != NULL) {
+ if (dev->domainsearch != NULL)
+ free(dev->domainsearch);
+ dev->domainsearch = ret;
+ }
+ }
+
+ if (ext121_len > 0) {
+ struct route *ret;
+
+ ret = bootp_ext121_decode(ext121_buf, ext121_len);
+ if (ret != NULL) {
+ struct route *cur = dev->routes;
+ struct route *next;
+ while (cur != NULL) {
+ next = cur->next;
+ free(cur);
+ cur = next;
+ }
+ dev->routes = ret;
+ }
+ }
+
+ /*
+ * Got packet.
+ */
+ return 1;
+}
+
+/*
+ * Receive a bootp reply and parse packet
+ * Returns:
+ *-1 = Error in packet_recv, try again later
+ * 0 = Unexpected packet, discarded
+ * 1 = Correctly received and parsed packet
+ */
+int bootp_recv_reply(struct netdev *dev)
+{
+ struct bootp_hdr bootp;
+ uint8_t bootp_options[BOOTP_EXTS_SIZE];
+ struct iovec iov[] = {
+ /* [0] = ip + udp headers */
+ [1] = {&bootp, sizeof(struct bootp_hdr)},
+ [2] = {bootp_options, sizeof(bootp_options)}
+ };
+ int ret;
+
+ ret = packet_recv(dev, iov, 3);
+ if (ret <= 0)
+ return ret;
+
+ if (ret < sizeof(struct bootp_hdr) ||
+ bootp.op != BOOTP_REPLY || /* RFC951 7.5 */
+ bootp.xid != dev->bootp.xid ||
+ memcmp(bootp.chaddr, dev->hwaddr, 16))
+ return 0;
+
+ ret -= sizeof(struct bootp_hdr);
+
+ return bootp_parse(dev, &bootp, bootp_options, ret);
+}
+
+/*
+ * Initialise interface for bootp.
+ */
+int bootp_init_if(struct netdev *dev)
+{
+ short flags;
+
+ /*
+ * Get the device flags
+ */
+ if (netdev_getflags(dev, &flags))
+ return -1;
+
+ /*
+ * We can't do DHCP nor BOOTP if this device
+ * doesn't support broadcast.
+ */
+ if (dev->mtu < 364 || (flags & IFF_BROADCAST) == 0) {
+ dev->caps &= ~(CAP_BOOTP | CAP_DHCP);
+ return 0;
+ }
+
+ /*
+ * Get a random XID
+ */
+ dev->bootp.xid = (uint32_t) lrand48();
+ dev->open_time = time(NULL);
+
+ return 0;
+}
diff --git a/usr/kinit/ipconfig/bootp_proto.h b/usr/kinit/ipconfig/bootp_proto.h
new file mode 100644
index 0000000..60873ce
--- /dev/null
+++ b/usr/kinit/ipconfig/bootp_proto.h
@@ -0,0 +1,10 @@
+#ifndef IPCONFIG_BOOTP_PROTO_H
+#define IPCONFIG_BOOTP_PROTO_H
+
+int bootp_send_request(struct netdev *dev);
+int bootp_recv_reply(struct netdev *dev);
+int bootp_parse(struct netdev *dev, struct bootp_hdr *hdr, uint8_t * exts,
+ int extlen);
+int bootp_init_if(struct netdev *dev);
+
+#endif /* IPCONFIG_BOOTP_PROTO_H */
diff --git a/usr/kinit/ipconfig/dhcp_proto.c b/usr/kinit/ipconfig/dhcp_proto.c
new file mode 100644
index 0000000..4e560b8
--- /dev/null
+++ b/usr/kinit/ipconfig/dhcp_proto.c
@@ -0,0 +1,301 @@
+/*
+ * DHCP RFC 2131 and 2132
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "dhcp_proto.h"
+#include "packet.h"
+
+static uint8_t dhcp_params[] = {
+ 1, /* subnet mask */
+ 3, /* default gateway */
+ 6, /* DNS server */
+ 12, /* host name */
+ 15, /* domain name */
+ 17, /* root path */
+ 26, /* interface mtu */
+ 28, /* broadcast addr */
+ 40, /* NIS domain name (why?) */
+ 119, /* Domain Search Option */
+ 121, /* Classless Static Route Option (RFC3442) */
+};
+
+static uint8_t dhcp_discover_hdr[] = {
+ 99, 130, 83, 99, /* bootp cookie */
+ 53, 1, DHCPDISCOVER, /* dhcp message type */
+ 55, sizeof(dhcp_params), /* parameter list */
+};
+
+static uint8_t dhcp_request_hdr[] = {
+ 99, 130, 83, 99, /* boot cookie */
+ 53, 1, DHCPREQUEST, /* dhcp message type */
+#define SERVER_IP_OFF 9
+ 54, 4, 0, 0, 0, 0, /* server IP */
+#define REQ_IP_OFF 15
+ 50, 4, 0, 0, 0, 0, /* requested IP address */
+ 55, sizeof(dhcp_params), /* parameter list */
+};
+
+static uint8_t dhcp_end[] = {
+ 255,
+};
+
+/* Both iovecs below have to have the same structure, since dhcp_send()
+ pokes at the internals */
+#define DHCP_IOV_LEN 8
+
+static struct iovec dhcp_discover_iov[DHCP_IOV_LEN] = {
+ /* [0] = ip + udp header */
+ /* [1] = bootp header */
+ [2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)},
+ [3] = {dhcp_params, sizeof(dhcp_params)},
+ /* [4] = optional vendor class */
+ /* [5] = optional hostname */
+ /* [6] = {dhcp_end, sizeof(dhcp_end)} */
+ /* [7] = optional padding */
+};
+
+static struct iovec dhcp_request_iov[DHCP_IOV_LEN] = {
+ /* [0] = ip + udp header */
+ /* [1] = bootp header */
+ [2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)},
+ [3] = {dhcp_params, sizeof(dhcp_params)},
+ /* [4] = optional vendor class */
+ /* [5] = optional hostname */
+ /* [6] = {dhcp_end, sizeof(dhcp_end)} */
+ /* [7] = optional padding */
+};
+
+/*
+ * Parse a DHCP response packet
+ * Returns:
+ * 0 = Unexpected packet, not parsed
+ * 2 = DHCPOFFER (from dhcp_proto.h)
+ * 5 = DHCPACK
+ * 6 = DHCPNACK
+ */
+static int dhcp_parse(struct netdev *dev, struct bootp_hdr *hdr,
+ uint8_t *exts, int extlen)
+{
+ uint8_t type = 0;
+ uint32_t serverid = INADDR_NONE;
+ uint32_t leasetime = 0;
+ int ret = 0;
+
+ if (extlen >= 4 && exts[0] == 99 && exts[1] == 130 &&
+ exts[2] == 83 && exts[3] == 99) {
+ uint8_t *ext;
+
+ for (ext = exts + 4; ext - exts < extlen;) {
+ int len;
+ uint8_t opt = *ext++;
+
+ if (opt == 0)
+ continue;
+ else if (opt == 255)
+ break;
+
+ if (ext - exts >= extlen)
+ break;
+ len = *ext++;
+
+ if (ext - exts + len > extlen)
+ break;
+ switch (opt) {
+ case 51: /* IP Address Lease Time */
+ if (len == 4)
+ leasetime = ntohl(*(uint32_t *)ext);
+ break;
+ case 53: /* DHCP Message Type */
+ if (len == 1)
+ type = *ext;
+ break;
+ case 54: /* Server Identifier */
+ if (len == 4)
+ memcpy(&serverid, ext, 4);
+ break;
+ }
+ ext += len;
+ }
+ }
+
+ switch (type) {
+ case DHCPOFFER:
+ ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0;
+ if (ret == DHCPOFFER && serverid != INADDR_NONE)
+ dev->serverid = serverid;
+ dprintf("\n dhcp offer\n");
+ break;
+
+ case DHCPACK:
+ dev->dhcpleasetime = leasetime;
+ ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0;
+ dprintf("\n dhcp ack\n");
+ break;
+
+ case DHCPNAK:
+ ret = DHCPNAK;
+ dprintf("\n dhcp nak\n");
+ break;
+ }
+ return ret;
+}
+
+/*
+ * Receive and parse a DHCP packet
+ * Returns:
+ *-1 = Error in packet_recv, try again later
+ * 0 = Unexpected packet, discarded
+ * 2 = DHCPOFFER (from dhcp_proto.h)
+ * 5 = DHCPACK
+ * 6 = DHCPNACK
+ */
+static int dhcp_recv(struct netdev *dev)
+{
+ struct bootp_hdr bootp;
+ uint8_t dhcp_options[BOOTP_EXTS_SIZE];
+ struct iovec iov[] = {
+ /* [0] = ip + udp header */
+ [1] = {&bootp, sizeof(struct bootp_hdr)},
+ [2] = {dhcp_options, sizeof(dhcp_options)}
+ };
+ int ret;
+
+ ret = packet_recv(dev, iov, 3);
+ if (ret <= 0)
+ return ret;
+
+ dprintf("\n dhcp xid %08x ", dev->bootp.xid);
+
+ if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY ||
+ /* RFC951 7.5 */ bootp.xid != dev->bootp.xid ||
+ memcmp(bootp.chaddr, dev->hwaddr, 16))
+ return 0;
+
+ ret -= sizeof(struct bootp_hdr);
+
+ return dhcp_parse(dev, &bootp, dhcp_options, ret);
+}
+
+static int dhcp_send(struct netdev *dev, struct iovec *vec)
+{
+ struct bootp_hdr bootp;
+ char dhcp_hostname[SYS_NMLN+2];
+ uint8_t padding[BOOTP_MIN_LEN - sizeof(struct bootp_hdr)];
+ int padding_len;
+ int i = 4;
+ int j;
+
+ memset(&bootp, 0, sizeof(struct bootp_hdr));
+
+ bootp.op = BOOTP_REQUEST;
+ bootp.htype = dev->hwtype;
+ bootp.hlen = dev->hwlen;
+ bootp.xid = dev->bootp.xid;
+ bootp.ciaddr = INADDR_ANY;
+ /* yiaddr should always be set to 0 for the messages we're likely
+ * to send as a DHCP client: DHCPDISCOVER, DHCPREQUEST, DHCPDECLINE,
+ * DHCPINFORM, DHCPRELEASE
+ * cf. RFC2131 section 4.1.1, table 5.
+ */
+ bootp.yiaddr = INADDR_ANY;
+ bootp.giaddr = INADDR_ANY;
+ bootp.flags = htons(0x8000);
+ bootp.secs = htons(time(NULL) - dev->open_time);
+ memcpy(bootp.chaddr, dev->hwaddr, 16);
+
+ vec[1].iov_base = &bootp;
+ vec[1].iov_len = sizeof(struct bootp_hdr);
+
+ dprintf("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs));
+
+ if (vendor_class_identifier_len > 2) {
+ vec[i].iov_base = vendor_class_identifier;
+ vec[i].iov_len = vendor_class_identifier_len;
+ i++;
+
+ dprintf("vendor_class_identifier \"%.*s\" ",
+ vendor_class_identifier_len-2,
+ vendor_class_identifier+2);
+ }
+
+ if (dev->reqhostname[0] != '\0') {
+ int len = strlen(dev->reqhostname);
+ dhcp_hostname[0] = 12;
+ dhcp_hostname[1] = len;
+ memcpy(dhcp_hostname+2, dev->reqhostname, len);
+
+ vec[i].iov_base = dhcp_hostname;
+ vec[i].iov_len = len+2;
+ i++;
+
+ printf("hostname %.*s ", len, dhcp_hostname+2);
+ }
+
+ vec[i].iov_base = dhcp_end;
+ vec[i].iov_len = sizeof(dhcp_end);
+
+ /* Append padding if DHCP packet length is shorter than BOOTP_MIN_LEN */
+ padding_len = sizeof(padding);
+ for (j = 2; j <= i; j++)
+ padding_len -= vec[j].iov_len;
+ if (padding_len > 0) {
+ memset(padding, 0, padding_len);
+ i++;
+ vec[i].iov_base = padding;
+ vec[i].iov_len = padding_len;
+ }
+
+ return packet_send(dev, vec, i + 1);
+}
+
+/*
+ * Send a DHCP discover packet
+ */
+int dhcp_send_discover(struct netdev *dev)
+{
+ dev->ip_addr = INADDR_ANY;
+ dev->ip_gateway = INADDR_ANY;
+
+ dprintf("-> dhcp discover ");
+
+ return dhcp_send(dev, dhcp_discover_iov);
+}
+
+/*
+ * Receive a DHCP offer packet
+ */
+int dhcp_recv_offer(struct netdev *dev)
+{
+ return dhcp_recv(dev);
+}
+
+/*
+ * Send a DHCP request packet
+ */
+int dhcp_send_request(struct netdev *dev)
+{
+ memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4);
+ memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4);
+
+ dprintf("-> dhcp request ");
+
+ return dhcp_send(dev, dhcp_request_iov);
+}
+
+/*
+ * Receive a DHCP ack packet
+ */
+int dhcp_recv_ack(struct netdev *dev)
+{
+ return dhcp_recv(dev);
+}
diff --git a/usr/kinit/ipconfig/dhcp_proto.h b/usr/kinit/ipconfig/dhcp_proto.h
new file mode 100644
index 0000000..0fba92f
--- /dev/null
+++ b/usr/kinit/ipconfig/dhcp_proto.h
@@ -0,0 +1,19 @@
+#ifndef IPCONFIG_DHCP_PROTO_H
+#define IPCONFIG_DHCP_PROTO_H
+
+/* DHCP message types */
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+int dhcp_send_discover(struct netdev *dev);
+int dhcp_recv_offer(struct netdev *dev);
+int dhcp_send_request(struct netdev *dev);
+int dhcp_recv_ack(struct netdev *dev);
+
+#endif /* IPCONFIG_DHCP_PROTO_H */
diff --git a/usr/kinit/ipconfig/ipconfig.h b/usr/kinit/ipconfig/ipconfig.h
new file mode 100644
index 0000000..d1d7e42
--- /dev/null
+++ b/usr/kinit/ipconfig/ipconfig.h
@@ -0,0 +1,25 @@
+#ifndef IPCONFIG_IPCONFIG_H
+#define IPCONFIG_IPCONFIG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOCAL_PORT 68
+#define REMOTE_PORT (LOCAL_PORT - 1)
+
+extern uint16_t cfg_local_port;
+extern uint16_t cfg_remote_port;
+
+extern char vendor_class_identifier[];
+extern int vendor_class_identifier_len;
+
+int ipconfig_main(int argc, char *argv[]);
+uint32_t ipconfig_server_address(void *next);
+
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
+#endif /* IPCONFIG_IPCONFIG_H */
diff --git a/usr/kinit/ipconfig/main.c b/usr/kinit/ipconfig/main.c
new file mode 100644
index 0000000..64c5398
--- /dev/null
+++ b/usr/kinit/ipconfig/main.c
@@ -0,0 +1,924 @@
+#include <poll.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sysinfo.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h> /* for getopts */
+
+#include <net/if_arp.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "bootp_packet.h"
+#include "bootp_proto.h"
+#include "dhcp_proto.h"
+#include "packet.h"
+
+static const char sysfs_class_net[] = "/sys/class/net";
+static const char *progname;
+static jmp_buf abort_buf;
+static char do_not_config;
+static unsigned int default_caps = CAP_DHCP | CAP_BOOTP | CAP_RARP;
+static int loop_timeout = -1;
+static int configured;
+static int bringup_first = 0;
+static int n_devices = 0;
+
+/* DHCP vendor class identifier */
+char vendor_class_identifier[260];
+int vendor_class_identifier_len;
+
+struct state {
+ int state;
+ int restart_state;
+ time_t expire;
+ int retry_period;
+
+ struct netdev *dev;
+ struct state *next;
+};
+
+/* #define PROTO_x : for uint8_t proto of struct netdev */
+struct protoinfo {
+ char *name;
+} protoinfos[] = {
+#define PROTO_NONE 0
+ {"none"},
+#define PROTO_BOOTP 1
+ {"bootp"},
+#define PROTO_DHCP 2
+ {"dhcp"},
+#define PROTO_RARP 3
+ {"rarp"}
+};
+
+static inline const char *my_inet_ntoa(uint32_t addr)
+{
+ struct in_addr a;
+
+ a.s_addr = addr;
+
+ return inet_ntoa(a);
+}
+
+static void print_device_config(struct netdev *dev)
+{
+ int dns0_spaces;
+ int dns1_spaces;
+ printf("IP-Config: %s complete", dev->name);
+ if (dev->proto == PROTO_BOOTP || dev->proto == PROTO_DHCP)
+ printf(" (%s from %s)", protoinfos[dev->proto].name,
+ my_inet_ntoa(dev->serverid ?
+ dev->serverid : dev->ip_server));
+
+ printf(":\n address: %-16s ", my_inet_ntoa(dev->ip_addr));
+ printf("broadcast: %-16s ", my_inet_ntoa(dev->ip_broadcast));
+ printf("netmask: %-16s\n", my_inet_ntoa(dev->ip_netmask));
+ if (dev->routes != NULL) {
+ struct route *cur;
+ char *delim = "";
+ printf(" routes :");
+ for (cur = dev->routes; cur != NULL; cur = cur->next) {
+ printf("%s %s/%u", delim, my_inet_ntoa(cur->subnet), cur->netmask_width);
+ if (cur->gateway != 0) {
+ printf(" via %s", my_inet_ntoa(cur->gateway));
+ }
+ delim = ",";
+ }
+ printf("\n");
+ dns0_spaces = 3;
+ dns1_spaces = 5;
+ } else {
+ printf(" gateway: %-16s", my_inet_ntoa(dev->ip_gateway));
+ dns0_spaces = 5;
+ dns1_spaces = 3;
+ }
+ printf(" dns0%*c: %-16s", dns0_spaces, ' ', my_inet_ntoa(dev->ip_nameserver[0]));
+ printf(" dns1%*c: %-16s\n", dns1_spaces, ' ', my_inet_ntoa(dev->ip_nameserver[1]));
+ if (dev->hostname[0])
+ printf(" host : %-64s\n", dev->hostname);
+ if (dev->dnsdomainname[0])
+ printf(" domain : %-64s\n", dev->dnsdomainname);
+ if (dev->nisdomainname[0])
+ printf(" nisdomain: %-64s\n", dev->nisdomainname);
+ printf(" rootserver: %s ", my_inet_ntoa(dev->ip_server));
+ printf("rootpath: %s\n", dev->bootpath);
+ printf(" filename : %s\n", dev->filename);
+}
+
+static void configure_device(struct netdev *dev)
+{
+ if (do_not_config)
+ return;
+
+ if (netdev_setmtu(dev))
+ printf("IP-Config: failed to set MTU on %s to %u\n",
+ dev->name, dev->mtu);
+
+ if (netdev_setaddress(dev))
+ printf("IP-Config: failed to set addresses on %s\n",
+ dev->name);
+ if (netdev_setroutes(dev))
+ printf("IP-Config: failed to set routes on %s\n",
+ dev->name);
+ if (dev->hostname[0] &&
+ sethostname(dev->hostname, strlen(dev->hostname)))
+ printf("IP-Config: failed to set hostname '%s' from %s\n",
+ dev->hostname, dev->name);
+}
+
+/*
+ * Escape shell varialbes in git style:
+ * Always start with a single quote ('), then leave all characters
+ * except ' and ! unchanged.
+ */
+static void write_option(FILE *f, const char *name, const char *chr)
+{
+
+ fprintf(f, "%s='", name);
+ while (*chr) {
+ switch (*chr) {
+ case '!':
+ case '\'':
+ fprintf(f, "'\\%c'", *chr);
+ break;
+ default:
+ fprintf(f, "%c", *chr);
+ break;
+ }
+ ++chr;
+ }
+ fprintf(f, "'\n");
+}
+
+static void dump_device_config(struct netdev *dev)
+{
+ char fn[40];
+ FILE *f;
+ /*
+ * char UINT64_MAX[] = "18446744073709551615";
+ * sizeof(UINT64_MAX)==21
+ */
+ char buf21[21];
+ const char path[] = "/run/";
+
+ snprintf(fn, sizeof(fn), "%snet-%s.conf", path, dev->name);
+ f = fopen(fn, "w");
+ if (f) {
+ write_option(f, "DEVICE", dev->name);
+ write_option(f, "PROTO", protoinfos[dev->proto].name);
+ write_option(f, "IPV4ADDR",
+ my_inet_ntoa(dev->ip_addr));
+ write_option(f, "IPV4BROADCAST",
+ my_inet_ntoa(dev->ip_broadcast));
+ write_option(f, "IPV4NETMASK",
+ my_inet_ntoa(dev->ip_netmask));
+ if (dev->routes != NULL) {
+ /* Use 6 digits to encode the index */
+ char key[23];
+ char value[19];
+ int i = 0;
+ struct route *cur;
+ for (cur = dev->routes; cur != NULL; cur = cur->next) {
+ snprintf(key, sizeof(key), "IPV4ROUTE%iSUBNET", i);
+ snprintf(value, sizeof(value), "%s/%u", my_inet_ntoa(cur->subnet), cur->netmask_width);
+ write_option(f, key, value);
+ snprintf(key, sizeof(key), "IPV4ROUTE%iGATEWAY", i);
+ write_option(f, key, my_inet_ntoa(cur->gateway));
+ i++;
+ }
+ } else {
+ write_option(f, "IPV4GATEWAY",
+ my_inet_ntoa(dev->ip_gateway));
+ }
+ write_option(f, "IPV4DNS0",
+ my_inet_ntoa(dev->ip_nameserver[0]));
+ write_option(f, "IPV4DNS1",
+ my_inet_ntoa(dev->ip_nameserver[1]));
+ write_option(f, "HOSTNAME", dev->hostname);
+ write_option(f, "DNSDOMAIN", dev->dnsdomainname);
+ write_option(f, "NISDOMAIN", dev->nisdomainname);
+ write_option(f, "ROOTSERVER",
+ my_inet_ntoa(dev->ip_server));
+ write_option(f, "ROOTPATH", dev->bootpath);
+ write_option(f, "filename", dev->filename);
+ sprintf(buf21, "%ld", (long)dev->uptime);
+ write_option(f, "UPTIME", buf21);
+ sprintf(buf21, "%u", (unsigned int)dev->dhcpleasetime);
+ write_option(f, "DHCPLEASETIME", buf21);
+ write_option(f, "DOMAINSEARCH", dev->domainsearch == NULL ?
+ "" : dev->domainsearch);
+ fclose(f);
+ }
+}
+
+static uint32_t inet_class_netmask(uint32_t ip)
+{
+ ip = ntohl(ip);
+ if (IN_CLASSA(ip))
+ return htonl(IN_CLASSA_NET);
+ if (IN_CLASSB(ip))
+ return htonl(IN_CLASSB_NET);
+ if (IN_CLASSC(ip))
+ return htonl(IN_CLASSC_NET);
+ return INADDR_ANY;
+}
+
+static void postprocess_device(struct netdev *dev)
+{
+ if (dev->ip_netmask == INADDR_ANY) {
+ dev->ip_netmask = inet_class_netmask(dev->ip_addr);
+ printf("IP-Config: %s guessed netmask %s\n",
+ dev->name, my_inet_ntoa(dev->ip_netmask));
+ }
+ if (dev->ip_broadcast == INADDR_ANY) {
+ dev->ip_broadcast =
+ (dev->ip_addr & dev->ip_netmask) | ~dev->ip_netmask;
+ printf("IP-Config: %s guessed broadcast address %s\n",
+ dev->name, my_inet_ntoa(dev->ip_broadcast));
+ }
+}
+
+static void complete_device(struct netdev *dev)
+{
+ struct sysinfo info;
+
+ if (!sysinfo(&info))
+ dev->uptime = info.uptime;
+ postprocess_device(dev);
+ configure_device(dev);
+ dump_device_config(dev);
+ print_device_config(dev);
+ packet_close(dev);
+
+ ++configured;
+
+ dev->next = ifaces;
+ ifaces = dev;
+}
+
+/*
+ * Returns:
+ * 0 = Not handled, try again later
+ * 1 = Handled
+ */
+static int process_receive_event(struct state *s, time_t now)
+{
+ int handled = 1;
+
+ switch (s->state) {
+ case DEVST_ERROR:
+ return 0; /* Not handled */
+ case DEVST_COMPLETE:
+ return 0; /* Not handled as already configured */
+
+ case DEVST_BOOTP:
+ s->restart_state = DEVST_BOOTP;
+ switch (bootp_recv_reply(s->dev)) {
+ case -1:
+ s->state = DEVST_ERROR;
+ break;
+ case 0:
+ handled = 0;
+ break;
+ case 1:
+ s->state = DEVST_COMPLETE;
+ s->dev->proto = PROTO_BOOTP;
+ dprintf("\n bootp reply\n");
+ break;
+ }
+ break;
+
+ case DEVST_DHCPDISC:
+ s->restart_state = DEVST_DHCPDISC;
+ switch (dhcp_recv_offer(s->dev)) {
+ case -1:
+ s->state = DEVST_ERROR;
+ break;
+ case 0:
+ handled = 0;
+ break;
+ case DHCPOFFER: /* Offer received */
+ s->state = DEVST_DHCPREQ;
+ dhcp_send_request(s->dev);
+ break;
+ }
+ break;
+
+ case DEVST_DHCPREQ:
+ s->restart_state = DEVST_DHCPDISC;
+ switch (dhcp_recv_ack(s->dev)) {
+ case -1: /* error */
+ s->state = DEVST_ERROR;
+ break;
+ case 0:
+ handled = 0;
+ break;
+ case DHCPACK: /* ACK received */
+ s->state = DEVST_COMPLETE;
+ s->dev->proto = PROTO_DHCP;
+ break;
+ case DHCPNAK: /* NAK received */
+ s->state = DEVST_DHCPDISC;
+ break;
+ }
+ break;
+
+ default:
+ dprintf("\n");
+ handled = 0;
+ break;
+ }
+
+ switch (s->state) {
+ case DEVST_COMPLETE:
+ complete_device(s->dev);
+ break;
+
+ case DEVST_ERROR:
+ /* error occurred, try again in 10 seconds */
+ s->expire = now + 10;
+ break;
+ }
+
+ return handled;
+}
+
+static void process_timeout_event(struct state *s, time_t now)
+{
+ int ret = 0;
+
+ /*
+ * If we had an error, restore a sane state to
+ * restart from.
+ */
+ if (s->state == DEVST_ERROR)
+ s->state = s->restart_state;
+
+ /*
+ * Now send a packet depending on our state.
+ */
+ switch (s->state) {
+ case DEVST_BOOTP:
+ ret = bootp_send_request(s->dev);
+ s->restart_state = DEVST_BOOTP;
+ break;
+
+ case DEVST_DHCPDISC:
+ ret = dhcp_send_discover(s->dev);
+ s->restart_state = DEVST_DHCPDISC;
+ break;
+
+ case DEVST_DHCPREQ:
+ ret = dhcp_send_request(s->dev);
+ s->restart_state = DEVST_DHCPDISC;
+ break;
+ }
+
+ if (ret == -1) {
+ s->state = DEVST_ERROR;
+ s->expire = now + 1;
+ } else {
+ s->expire = now + s->retry_period;
+
+ s->retry_period *= 2;
+ if (s->retry_period > 60)
+ s->retry_period = 60;
+ }
+}
+
+static void process_error_event(struct state *s, time_t now)
+{
+ s->state = DEVST_ERROR;
+ s->expire = now + 1;
+}
+
+static struct state *slist;
+struct netdev *ifaces;
+
+/*
+ * Returns:
+ * 0 = No dhcp/bootp packet was received
+ * 1 = A packet was received and handled
+ */
+static int do_pkt_recv(int nr, struct pollfd *fds, time_t now)
+{
+ int i, ret = 0;
+ struct state *s;
+
+ for (i = 0, s = slist; s && nr; s = s->next) {
+ if (s->dev->pkt_fd != fds[i].fd)
+ continue;
+ if (fds[i].revents) {
+ if (fds[i].revents & POLLRDNORM)
+ ret |= process_receive_event(s, now);
+ else
+ process_error_event(s, now);
+ nr--;
+ }
+ i++;
+ }
+ return ret;
+}
+
+static int loop(void)
+{
+ struct pollfd *fds;
+ struct state *s;
+ int i, nr = 0, rc = 0;
+ struct timeval now, prev;
+ time_t start;
+
+ fds = malloc(sizeof(struct pollfd) * n_devices);
+ if (!fds) {
+ fprintf(stderr, "malloc failed\n");
+ rc = -1;
+ goto bail;
+ }
+
+ memset(fds, 0, sizeof(*fds));
+
+ gettimeofday(&now, NULL);
+ start = now.tv_sec;
+ while (1) {
+ int timeout = 60;
+ int pending = 0;
+ int done = 0;
+ int timeout_ms;
+ int x;
+
+ for (i = 0, s = slist; s; s = s->next) {
+ dprintf("%s: state = %d\n", s->dev->name, s->state);
+
+ if (s->state == DEVST_COMPLETE) {
+ done++;
+ continue;
+ }
+
+ pending++;
+
+ if (s->expire - now.tv_sec <= 0) {
+ dprintf("timeout\n");
+ process_timeout_event(s, now.tv_sec);
+ }
+
+ if (s->state != DEVST_ERROR) {
+ fds[i].fd = s->dev->pkt_fd;
+ fds[i].events = POLLRDNORM;
+ i++;
+ }
+
+ if (timeout > s->expire - now.tv_sec)
+ timeout = s->expire - now.tv_sec;
+ }
+
+ if (pending == 0 || (bringup_first && done))
+ break;
+
+ timeout_ms = timeout * 1000;
+
+ for (x = 0; x < 2; x++) {
+ int delta_ms;
+
+ if (timeout_ms <= 0)
+ timeout_ms = 100;
+
+ nr = poll(fds, i, timeout_ms);
+ prev = now;
+ gettimeofday(&now, NULL);
+
+ if ((nr > 0) && do_pkt_recv(nr, fds, now.tv_sec))
+ break;
+
+ if (loop_timeout >= 0 &&
+ now.tv_sec - start >= loop_timeout) {
+ printf("IP-Config: no response after %d "
+ "secs - giving up\n", loop_timeout);
+ rc = -1;
+ goto bail;
+ }
+
+ delta_ms = (now.tv_sec - prev.tv_sec) * 1000;
+ delta_ms += (now.tv_usec - prev.tv_usec) / 1000;
+
+ dprintf("Delta: %d ms\n", delta_ms);
+
+ timeout_ms -= delta_ms;
+ }
+ }
+bail:
+ if (fds)
+ free(fds);
+ return rc;
+}
+
+static int add_one_dev(struct netdev *dev)
+{
+ struct state *state;
+
+ state = malloc(sizeof(struct state));
+ if (!state)
+ return -1;
+
+ state->dev = dev;
+ state->expire = time(NULL);
+ state->retry_period = 1;
+
+ /*
+ * Select the state that we start from.
+ */
+ if (dev->caps & CAP_DHCP && dev->ip_addr == INADDR_ANY)
+ state->restart_state = state->state = DEVST_DHCPDISC;
+ else if (dev->caps & CAP_DHCP)
+ state->restart_state = state->state = DEVST_DHCPREQ;
+ else if (dev->caps & CAP_BOOTP)
+ state->restart_state = state->state = DEVST_BOOTP;
+
+ state->next = slist;
+ slist = state;
+
+ n_devices++;
+
+ return 0;
+}
+
+static void parse_addr(uint32_t *addr, const char *ip)
+{
+ struct in_addr in;
+ if (inet_aton(ip, &in) == 0) {
+ fprintf(stderr, "%s: can't parse IP address '%s'\n",
+ progname, ip);
+ longjmp(abort_buf, 1);
+ }
+ *addr = in.s_addr;
+}
+
+static unsigned int parse_proto(const char *ip)
+{
+ unsigned int caps = 0;
+
+ if (*ip == '\0' || strcmp(ip, "on") == 0 || strcmp(ip, "any") == 0)
+ caps = CAP_BOOTP | CAP_DHCP | CAP_RARP;
+ else if (strcmp(ip, "both") == 0)
+ caps = CAP_BOOTP | CAP_RARP;
+ else if (strcmp(ip, "dhcp") == 0)
+ caps = CAP_BOOTP | CAP_DHCP;
+ else if (strcmp(ip, "bootp") == 0)
+ caps = CAP_BOOTP;
+ else if (strcmp(ip, "rarp") == 0)
+ caps = CAP_RARP;
+ else if (strcmp(ip, "none") == 0 || strcmp(ip, "static") == 0
+ || strcmp(ip, "off") == 0)
+ goto bail;
+ else {
+ fprintf(stderr, "%s: invalid protocol '%s'\n", progname, ip);
+ longjmp(abort_buf, 1);
+ }
+bail:
+ return caps;
+}
+
+static int add_all_devices(struct netdev *template);
+
+static int parse_device(struct netdev *dev, char *ip)
+{
+ char *cp;
+ int opt;
+ int is_ip = 0;
+
+ dprintf("IP-Config: parse_device: \"%s\"\n", ip);
+
+ if (strncmp(ip, "ip=", 3) == 0) {
+ ip += 3;
+ is_ip = 1;
+ } else if (strncmp(ip, "nfsaddrs=", 9) == 0) {
+ ip += 9;
+ is_ip = 1; /* Not sure about this...? */
+ }
+
+ if (!strchr(ip, ':')) {
+ /* Only one option, e.g. "ip=dhcp", or an interface name */
+ if (is_ip) {
+ dev->caps = parse_proto(ip);
+ bringup_first = 1;
+ } else {
+ dev->name = ip;
+ }
+ } else {
+ for (opt = 0; ip && *ip; ip = cp, opt++) {
+ if ((cp = strchr(ip, ':'))) {
+ *cp++ = '\0';
+ }
+ if (*ip == '\0')
+ continue;
+ dprintf("IP-Config: opt #%d: '%s'\n", opt, ip);
+ switch (opt) {
+ case 0:
+ parse_addr(&dev->ip_addr, ip);
+ dev->caps = 0;
+ break;
+ case 1:
+ parse_addr(&dev->ip_server, ip);
+ break;
+ case 2:
+ parse_addr(&dev->ip_gateway, ip);
+ break;
+ case 3:
+ parse_addr(&dev->ip_netmask, ip);
+ break;
+ case 4:
+ strncpy(dev->hostname, ip, SYS_NMLN - 1);
+ dev->hostname[SYS_NMLN - 1] = '\0';
+ memcpy(dev->reqhostname, dev->hostname,
+ SYS_NMLN);
+ break;
+ case 5:
+ dev->name = ip;
+ break;
+ case 6:
+ dev->caps = parse_proto(ip);
+ break;
+ case 7:
+ parse_addr(&dev->ip_nameserver[0], ip);
+ break;
+ case 8:
+ parse_addr(&dev->ip_nameserver[1], ip);
+ break;
+ case 9:
+ /* NTP server - ignore */
+ break;
+ }
+ }
+ }
+
+ if (dev->name == NULL ||
+ dev->name[0] == '\0' || strcmp(dev->name, "all") == 0) {
+ add_all_devices(dev);
+ bringup_first = 1;
+ return 0;
+ }
+ return 1;
+}
+
+static void bringup_device(struct netdev *dev)
+{
+ if (netdev_up(dev) == 0) {
+ if (dev->caps)
+ add_one_dev(dev);
+ else {
+ dev->proto = PROTO_NONE;
+ complete_device(dev);
+ }
+ }
+}
+
+static void bringup_one_dev(struct netdev *template, struct netdev *dev)
+{
+ if (template->ip_addr != INADDR_NONE)
+ dev->ip_addr = template->ip_addr;
+ if (template->ip_server != INADDR_NONE)
+ dev->ip_server = template->ip_server;
+ if (template->ip_gateway != INADDR_NONE)
+ dev->ip_gateway = template->ip_gateway;
+ if (template->ip_netmask != INADDR_NONE)
+ dev->ip_netmask = template->ip_netmask;
+ if (template->ip_nameserver[0] != INADDR_NONE)
+ dev->ip_nameserver[0] = template->ip_nameserver[0];
+ if (template->ip_nameserver[1] != INADDR_NONE)
+ dev->ip_nameserver[1] = template->ip_nameserver[1];
+ if (template->hostname[0] != '\0')
+ strcpy(dev->hostname, template->hostname);
+ if (template->reqhostname[0] != '\0')
+ strcpy(dev->reqhostname, template->reqhostname);
+ dev->caps &= template->caps;
+
+ bringup_device(dev);
+}
+
+static struct netdev *add_device(char *info)
+{
+ struct netdev *dev;
+ int i;
+
+ dev = malloc(sizeof(struct netdev));
+ if (dev == NULL) {
+ fprintf(stderr, "%s: out of memory\n", progname);
+ longjmp(abort_buf, 1);
+ }
+
+ memset(dev, 0, sizeof(struct netdev));
+ dev->caps = default_caps;
+
+ if (parse_device(dev, info) == 0)
+ goto bail;
+
+ if (netdev_init_if(dev) == -1)
+ goto bail;
+
+ if (bootp_init_if(dev) == -1)
+ goto bail;
+
+ if (packet_open(dev) == -1)
+ goto bail;
+
+ printf("IP-Config: %s hardware address", dev->name);
+ for (i = 0; i < dev->hwlen; i++)
+ printf("%c%02x", i == 0 ? ' ' : ':', dev->hwaddr[i]);
+ printf(" mtu %d%s%s\n", dev->mtu,
+ dev->caps & CAP_DHCP ? " DHCP" :
+ dev->caps & CAP_BOOTP ? " BOOTP" : "",
+ dev->caps & CAP_RARP ? " RARP" : "");
+ return dev;
+bail:
+ free(dev);
+ return NULL;
+}
+
+static int add_all_devices(struct netdev *template)
+{
+ DIR *d;
+ struct dirent *de;
+ struct netdev *dev;
+ char t[PATH_MAX], p[255];
+ int i, fd;
+ unsigned long flags;
+
+ d = opendir(sysfs_class_net);
+ if (!d)
+ return 0;
+
+ while ((de = readdir(d)) != NULL) {
+ /* This excludes devices beginning with dots or "dummy",
+ as well as . or .. */
+ if (de->d_name[0] == '.' || !strcmp(de->d_name, ".."))
+ continue;
+ i = snprintf(t, PATH_MAX - 1, "%s/%s/flags", sysfs_class_net,
+ de->d_name);
+ if (i < 0 || i >= PATH_MAX - 1)
+ continue;
+ t[i] = '\0';
+ fd = open(t, O_RDONLY);
+ if (fd < 0) {
+ perror(t);
+ continue;
+ }
+ i = read(fd, &p, sizeof(p) - 1);
+ close(fd);
+ if (i < 0) {
+ perror(t);
+ continue;
+ }
+ p[i] = '\0';
+ flags = strtoul(p, NULL, 0);
+ /* Heuristic for if this is a reasonable boot interface.
+ This is the same
+ logic the in-kernel ipconfig uses... */
+ if (!(flags & IFF_LOOPBACK) &&
+ (flags & (IFF_BROADCAST | IFF_POINTOPOINT))) {
+ dprintf("Trying to bring up %s\n", de->d_name);
+
+ dev = add_device(de->d_name);
+ if (!dev)
+ continue;
+ bringup_one_dev(template, dev);
+ }
+ }
+ closedir(d);
+ return 1;
+}
+
+static int check_autoconfig(void)
+{
+ int ndev = 0, nauto = 0;
+ struct state *s;
+
+ for (s = slist; s; s = s->next) {
+ ndev++;
+ if (s->dev->caps)
+ nauto++;
+ }
+
+ if (ndev == 0) {
+ if (configured == 0) {
+ fprintf(stderr, "%s: no devices to configure\n",
+ progname);
+ longjmp(abort_buf, 1);
+ }
+ }
+
+ return nauto;
+}
+
+static void set_vendor_identifier(const char *id)
+{
+ int len = strlen(id);
+ if (len >= 255) {
+ fprintf(stderr,
+ "%s: invalid vendor class identifier: "
+ "%s\n", progname, id);
+ longjmp(abort_buf, 1);
+ }
+ memcpy(vendor_class_identifier+2, id, len);
+ vendor_class_identifier[0] = 60;
+ vendor_class_identifier[1] = len;
+ vendor_class_identifier_len = len+2;
+}
+
+int main(int argc, char *argv[])
+ __attribute__ ((weak, alias("ipconfig_main")));
+
+int ipconfig_main(int argc, char *argv[])
+{
+ struct netdev *dev;
+ int c, port;
+ int err = 0;
+
+ /* If progname is set we're invoked from another program */
+ if (!progname) {
+ struct timeval now;
+ progname = argv[0];
+ gettimeofday(&now, NULL);
+ srand48(now.tv_usec ^ (now.tv_sec << 24));
+ }
+
+ if ((err = setjmp(abort_buf)))
+ return err;
+
+ /* Default vendor identifier */
+ set_vendor_identifier("Linux ipconfig");
+
+ do {
+ c = getopt(argc, argv, "c:d:i:onp:t:");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 'c':
+ default_caps = parse_proto(optarg);
+ break;
+ case 'p':
+ port = atoi(optarg);
+ if (port <= 0 || port > USHRT_MAX) {
+ fprintf(stderr,
+ "%s: invalid port number %d\n",
+ progname, port);
+ longjmp(abort_buf, 1);
+ }
+ cfg_local_port = port;
+ cfg_remote_port = cfg_local_port - 1;
+ break;
+ case 't':
+ loop_timeout = atoi(optarg);
+ if (loop_timeout < 0) {
+ fprintf(stderr,
+ "%s: invalid timeout %d\n",
+ progname, loop_timeout);
+ longjmp(abort_buf, 1);
+ }
+ break;
+ case 'i':
+ set_vendor_identifier(optarg);
+ break;
+ case 'o':
+ bringup_first = 1;
+ break;
+ case 'n':
+ do_not_config = 1;
+ break;
+ case 'd':
+ dev = add_device(optarg);
+ if (dev)
+ bringup_device(dev);
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ longjmp(abort_buf, 1);
+ }
+ } while (1);
+
+ for (c = optind; c < argc; c++) {
+ dev = add_device(argv[c]);
+ if (dev)
+ bringup_device(dev);
+ }
+
+ if (check_autoconfig()) {
+ if (cfg_local_port != LOCAL_PORT) {
+ printf("IP-Config: binding source port to %d, "
+ "dest to %d\n",
+ cfg_local_port, cfg_remote_port);
+ }
+ err = loop();
+ }
+
+ return err;
+}
diff --git a/usr/kinit/ipconfig/netdev.c b/usr/kinit/ipconfig/netdev.c
new file mode 100644
index 0000000..de87f96
--- /dev/null
+++ b/usr/kinit/ipconfig/netdev.c
@@ -0,0 +1,279 @@
+/*
+ * ioctl-based device configuration
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/route.h>
+#include <linux/sockios.h>
+
+#include "netdev.h"
+
+static int cfd = -1;
+
+static void copy_name(struct netdev *dev, struct ifreq *ifr)
+{
+ strncpy(ifr->ifr_name, dev->name, sizeof(ifr->ifr_name));
+ ifr->ifr_name[sizeof(ifr->ifr_name) - 1] = '\0';
+}
+
+int netdev_getflags(struct netdev *dev, short *flags)
+{
+ struct ifreq ifr;
+
+ copy_name(dev, &ifr);
+
+ if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+ perror("SIOCGIFFLAGS");
+ return -1;
+ }
+
+ *flags = ifr.ifr_flags;
+ return 0;
+}
+
+static int netdev_sif_addr(struct ifreq *ifr, int cmd, uint32_t addr)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = addr;
+
+ memcpy(&ifr->ifr_addr, &sin, sizeof sin);
+
+ return ioctl(cfd, cmd, ifr);
+}
+
+int netdev_setaddress(struct netdev *dev)
+{
+ struct ifreq ifr;
+
+ copy_name(dev, &ifr);
+
+ if (dev->ip_addr != INADDR_ANY &&
+ netdev_sif_addr(&ifr, SIOCSIFADDR, dev->ip_addr) == -1) {
+ perror("SIOCSIFADDR");
+ return -1;
+ }
+
+ if (dev->ip_broadcast != INADDR_ANY &&
+ netdev_sif_addr(&ifr, SIOCSIFBRDADDR, dev->ip_broadcast) == -1) {
+ perror("SIOCSIFBRDADDR");
+ return -1;
+ }
+
+ if (dev->ip_netmask != INADDR_ANY &&
+ netdev_sif_addr(&ifr, SIOCSIFNETMASK, dev->ip_netmask) == -1) {
+ perror("SIOCSIFNETMASK");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void set_s_addr(struct sockaddr *saddr, uint32_t ipaddr)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = ipaddr,
+ };
+ memcpy(saddr, &sin, sizeof sin);
+}
+
+int netdev_setroutes(struct netdev *dev)
+{
+ struct rtentry r;
+
+ /* RFC3442 demands:
+ If the DHCP server returns both a Classless Static Routes option and
+ a Router option, the DHCP client MUST ignore the Router option. */
+ if (dev->routes != NULL) {
+ struct route *cur;
+ for (cur = dev->routes; cur != NULL; cur = cur->next) {
+ memset(&r, 0, sizeof(r));
+
+ r.rt_dev = dev->name;
+ set_s_addr(&r.rt_dst, cur->subnet);
+ set_s_addr(&r.rt_gateway, cur->gateway);
+ set_s_addr(&r.rt_genmask, netdev_genmask(cur->netmask_width));
+ r.rt_flags = RTF_UP;
+ if (cur->gateway != 0) {
+ r.rt_flags |= RTF_GATEWAY;
+ }
+
+ if (ioctl(cfd, SIOCADDRT, &r) == -1 && errno != EEXIST) {
+ perror("SIOCADDRT");
+ return -1;
+ }
+ }
+ } else if (dev->ip_gateway != INADDR_ANY) {
+ memset(&r, 0, sizeof(r));
+
+ set_s_addr(&r.rt_dst, INADDR_ANY);
+ set_s_addr(&r.rt_gateway, dev->ip_gateway);
+ set_s_addr(&r.rt_genmask, INADDR_ANY);
+ r.rt_flags = RTF_UP | RTF_GATEWAY;
+
+ if (ioctl(cfd, SIOCADDRT, &r) == -1 && errno != EEXIST) {
+ perror("SIOCADDRT");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int netdev_setmtu(struct netdev *dev)
+{
+ struct ifreq ifr;
+
+ copy_name(dev, &ifr);
+ ifr.ifr_mtu = dev->mtu;
+
+ return ioctl(cfd, SIOCSIFMTU, &ifr);
+}
+
+static int netdev_gif_addr(struct ifreq *ifr, int cmd, uint32_t * ptr)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
+
+ if (ioctl(cfd, cmd, ifr) == -1)
+ return -1;
+
+ *ptr = sin->sin_addr.s_addr;
+
+ return 0;
+}
+
+int netdev_up(struct netdev *dev)
+{
+ struct ifreq ifr;
+
+ copy_name(dev, &ifr);
+
+ if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+ perror("SIOCGIFFLAGS");
+ return -1;
+ }
+
+ ifr.ifr_flags |= IFF_UP;
+
+ if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+int netdev_down(struct netdev *dev)
+{
+ struct ifreq ifr;
+
+ copy_name(dev, &ifr);
+
+ if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) {
+ perror("SIOCGIFFLAGS");
+ return -1;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+int netdev_init_if(struct netdev *dev)
+{
+ struct ifreq ifr;
+
+ if (cfd == -1)
+ cfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (cfd == -1) {
+ fprintf(stderr, "ipconfig: %s: socket(AF_INET): %s\n",
+ dev->name, strerror(errno));
+ return -1;
+ }
+
+ copy_name(dev, &ifr);
+
+ if (ioctl(cfd, SIOCGIFINDEX, &ifr) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFINDEX: %s\n",
+ dev->name, strerror(errno));
+ return -1;
+ }
+
+ dev->ifindex = ifr.ifr_ifindex;
+
+ if (ioctl(cfd, SIOCGIFMTU, &ifr) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFMTU: %s\n",
+ dev->name, strerror(errno));
+ return -1;
+ }
+
+ dev->mtu = ifr.ifr_mtu;
+
+ if (ioctl(cfd, SIOCGIFHWADDR, &ifr) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFHWADDR: %s\n",
+ dev->name, strerror(errno));
+ return -1;
+ }
+
+ dev->hwtype = ifr.ifr_hwaddr.sa_family;
+ dev->hwlen = 0;
+
+ switch (dev->hwtype) {
+ case ARPHRD_ETHER:
+ dev->hwlen = 6;
+ break;
+ case ARPHRD_EUI64:
+ dev->hwlen = 8;
+ break;
+ case ARPHRD_LOOPBACK:
+ dev->hwlen = 0;
+ break;
+ default:
+ return -1;
+ }
+
+ memcpy(dev->hwaddr, ifr.ifr_hwaddr.sa_data, dev->hwlen);
+ memset(dev->hwbrd, 0xff, dev->hwlen);
+
+ /*
+ * Try to get the current interface information.
+ */
+ if (dev->ip_addr == INADDR_NONE &&
+ netdev_gif_addr(&ifr, SIOCGIFADDR, &dev->ip_addr) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFADDR: %s\n",
+ dev->name, strerror(errno));
+ dev->ip_addr = 0;
+ dev->ip_broadcast = 0;
+ dev->ip_netmask = 0;
+ return 0;
+ }
+
+ if (dev->ip_broadcast == INADDR_NONE &&
+ netdev_gif_addr(&ifr, SIOCGIFBRDADDR, &dev->ip_broadcast) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFBRDADDR: %s\n",
+ dev->name, strerror(errno));
+ dev->ip_broadcast = 0;
+ }
+
+ if (dev->ip_netmask == INADDR_NONE &&
+ netdev_gif_addr(&ifr, SIOCGIFNETMASK, &dev->ip_netmask) == -1) {
+ fprintf(stderr, "ipconfig: %s: SIOCGIFNETMASK: %s\n",
+ dev->name, strerror(errno));
+ dev->ip_netmask = 0;
+ }
+
+ return 0;
+}
diff --git a/usr/kinit/ipconfig/netdev.h b/usr/kinit/ipconfig/netdev.h
new file mode 100644
index 0000000..dbc80cd
--- /dev/null
+++ b/usr/kinit/ipconfig/netdev.h
@@ -0,0 +1,107 @@
+#ifndef IPCONFIG_NETDEV_H
+#define IPCONFIG_NETDEV_H
+
+#include <arpa/inet.h>
+#include <sys/utsname.h>
+#include <net/if.h>
+
+#define BPLEN 256
+#define FNLEN 128 /* from DHCP RFC 2131 */
+
+struct route {
+ uint32_t subnet; /* subnet */
+ uint32_t netmask_width; /* subnet mask width */
+ uint32_t gateway; /* gateway */
+ struct route *next;
+};
+
+struct netdev {
+ char *name; /* Device name */
+ unsigned int ifindex; /* interface index */
+ unsigned int hwtype; /* ARPHRD_xxx */
+ unsigned int hwlen; /* HW address length */
+ uint8_t hwaddr[16]; /* HW address */
+ uint8_t hwbrd[16]; /* Broadcast HW address */
+ unsigned int mtu; /* Device mtu */
+ unsigned int caps; /* Capabilities */
+ time_t open_time;
+
+ struct { /* BOOTP/DHCP info */
+ int fd;
+ uint32_t xid;
+ uint32_t gateway; /* BOOTP/DHCP gateway */
+ } bootp;
+
+ struct { /* RARP information */
+ int fd;
+ } rarp;
+
+ uint8_t proto; /* a protocol used (e.g. PROTO_DHCP) */
+ uint32_t ip_addr; /* my address */
+ uint32_t ip_broadcast; /* broadcast address */
+ uint32_t ip_server; /* server address */
+ uint32_t ip_netmask; /* my subnet mask */
+ uint32_t ip_gateway; /* my gateway */
+ uint32_t ip_nameserver[2]; /* two nameservers */
+ uint32_t serverid; /* dhcp serverid */
+ uint32_t dhcpleasetime; /* duration in seconds */
+ char reqhostname[SYS_NMLN]; /* requested hostname */
+ char hostname[SYS_NMLN]; /* hostname */
+ char dnsdomainname[SYS_NMLN]; /* dns domain name */
+ char nisdomainname[SYS_NMLN]; /* nis domain name */
+ char bootpath[BPLEN]; /* boot path */
+ char filename[FNLEN]; /* filename */
+ char *domainsearch; /* decoded, NULL or malloc-ed */
+ struct route *routes; /* decoded, NULL or malloc-ed list */
+ long uptime; /* when complete configuration */
+ int pkt_fd; /* packet socket for this interface */
+ struct netdev *next; /* next configured i/f */
+};
+
+extern struct netdev *ifaces;
+
+/*
+ * Device capabilities
+ */
+#define CAP_BOOTP (1<<0)
+#define CAP_DHCP (1<<1)
+#define CAP_RARP (1<<2)
+
+/*
+ * Device states
+ */
+#define DEVST_UP 0
+#define DEVST_BOOTP 1
+#define DEVST_DHCPDISC 2
+#define DEVST_DHCPREQ 3
+#define DEVST_COMPLETE 4
+#define DEVST_ERROR 5
+
+int netdev_getflags(struct netdev *dev, short *flags);
+int netdev_setaddress(struct netdev *dev);
+int netdev_setroutes(struct netdev *dev);
+int netdev_up(struct netdev *dev);
+int netdev_down(struct netdev *dev);
+int netdev_init_if(struct netdev *dev);
+int netdev_setmtu(struct netdev *dev);
+
+static inline int netdev_running(struct netdev *dev)
+{
+ short flags;
+ int ret = netdev_getflags(dev, &flags);
+
+ return ret ? 0 : !!(flags & IFF_RUNNING);
+}
+
+static inline uint32_t netdev_genmask(uint32_t netmask_width)
+{
+ /* Map netmask width to network mask in network byte order.
+ Example: 24 -> "255.255.255.0" -> htonl(0xFFFFFF00) */
+ if (netmask_width == 0) {
+ return 0;
+ } else {
+ return htonl(~((1u << (32 - netmask_width)) - 1));
+ }
+}
+
+#endif /* IPCONFIG_NETDEV_H */
diff --git a/usr/kinit/ipconfig/packet.c b/usr/kinit/ipconfig/packet.c
new file mode 100644
index 0000000..2e1487d
--- /dev/null
+++ b/usr/kinit/ipconfig/packet.c
@@ -0,0 +1,278 @@
+#include <errno.h>/*XXX*/
+/*
+ * Packet socket handling glue.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if_packet.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <netpacket/packet.h>
+#include <asm/byteorder.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "ipconfig.h"
+#include "netdev.h"
+#include "packet.h"
+
+uint16_t cfg_local_port = LOCAL_PORT;
+uint16_t cfg_remote_port = REMOTE_PORT;
+
+int packet_open(struct netdev *dev)
+{
+ struct sockaddr_ll sll;
+ int fd, rv, one = 1;
+
+ /*
+ * Get a PACKET socket for IP traffic.
+ */
+ fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ if (fd == -1) {
+ perror("socket");
+ return -1;
+ }
+
+ /*
+ * We want to broadcast
+ */
+ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one,
+ sizeof(one)) == -1) {
+ perror("SO_BROADCAST");
+ close(fd);
+ return -1;
+ }
+
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = dev->ifindex;
+
+ rv = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
+ if (-1 == rv) {
+ perror("bind");
+ close(fd);
+ return -1;
+ }
+
+ dev->pkt_fd = fd;
+ return fd;
+}
+
+void packet_close(struct netdev *dev)
+{
+ close(dev->pkt_fd);
+ dev->pkt_fd = -1;
+}
+
+static unsigned int ip_checksum(uint16_t *hdr, int len)
+{
+ unsigned int chksum = 0;
+
+ while (len) {
+ chksum += *hdr++;
+ chksum += *hdr++;
+ len--;
+ }
+ chksum = (chksum & 0xffff) + (chksum >> 16);
+ chksum = (chksum & 0xffff) + (chksum >> 16);
+ return (~chksum) & 0xffff;
+}
+
+struct header {
+ struct iphdr ip;
+ struct udphdr udp;
+} __attribute__ ((packed, aligned(4)));
+
+static struct header ipudp_hdrs = {
+ .ip = {
+ .ihl = 5,
+ .version = IPVERSION,
+ .frag_off = __constant_htons(IP_DF),
+ .ttl = 64,
+ .protocol = IPPROTO_UDP,
+ .saddr = INADDR_ANY,
+ .daddr = INADDR_BROADCAST,
+ },
+ .udp = {
+ .source = __constant_htons(LOCAL_PORT),
+ .dest = __constant_htons(REMOTE_PORT),
+ .len = 0,
+ .check = 0,
+ },
+};
+
+#ifdef DEBUG /* Only used with dprintf() */
+static char *ntoa(uint32_t addr)
+{
+ struct in_addr in = { addr };
+ return inet_ntoa(in);
+}
+#endif /* DEBUG */
+
+/*
+ * Send a packet. The options are listed in iov[1...iov_len-1].
+ * iov[0] is reserved for the bootp packet header.
+ */
+int packet_send(struct netdev *dev, struct iovec *iov, int iov_len)
+{
+ struct sockaddr_ll sll;
+ struct msghdr msg;
+ int i, len = 0;
+
+ memset(&sll, 0, sizeof(sll));
+ msg.msg_name = &sll;
+ msg.msg_namelen = sizeof(sll);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = iov_len;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ if (cfg_local_port != LOCAL_PORT) {
+ ipudp_hdrs.udp.source = htons(cfg_local_port);
+ ipudp_hdrs.udp.dest = htons(cfg_remote_port);
+ }
+
+ dprintf("\n udp src %d dst %d", ntohs(ipudp_hdrs.udp.source),
+ ntohs(ipudp_hdrs.udp.dest));
+
+ dprintf("\n ip src %s ", ntoa(ipudp_hdrs.ip.saddr));
+ dprintf("dst %s ", ntoa(ipudp_hdrs.ip.daddr));
+
+ /*
+ * Glue in the ip+udp header iovec
+ */
+ iov[0].iov_base = &ipudp_hdrs;
+ iov[0].iov_len = sizeof(struct header);
+
+ for (i = 0; i < iov_len; i++)
+ len += iov[i].iov_len;
+
+ sll.sll_family = AF_PACKET;
+ sll.sll_protocol = htons(ETH_P_IP);
+ sll.sll_ifindex = dev->ifindex;
+ sll.sll_hatype = dev->hwtype;
+ sll.sll_pkttype = PACKET_BROADCAST;
+ sll.sll_halen = dev->hwlen;
+ memcpy(sll.sll_addr, dev->hwbrd, dev->hwlen);
+
+ ipudp_hdrs.ip.tot_len = htons(len);
+ ipudp_hdrs.ip.check = 0;
+ ipudp_hdrs.ip.check = ip_checksum((uint16_t *) &ipudp_hdrs.ip,
+ ipudp_hdrs.ip.ihl);
+
+ ipudp_hdrs.udp.len = htons(len - sizeof(struct iphdr));
+
+ dprintf("\n bytes %d\n", len);
+
+ return sendmsg(dev->pkt_fd, &msg, 0);
+}
+
+void packet_discard(struct netdev *dev)
+{
+ struct iphdr iph;
+ struct sockaddr_ll sll;
+ socklen_t sllen = sizeof(sll);
+
+ sll.sll_ifindex = dev->ifindex;
+
+ recvfrom(dev->pkt_fd, &iph, sizeof(iph), 0,
+ (struct sockaddr *)&sll, &sllen);
+}
+
+/*
+ * Receive a bootp packet. The options are listed in iov[1...iov_len].
+ * iov[0] must point to the bootp packet header.
+ * Returns:
+ * -1 = Error, try again later
+* 0 = Discarded packet (non-DHCP/BOOTP traffic)
+ * >0 = Size of packet
+ */
+int packet_recv(struct netdev *dev, struct iovec *iov, int iov_len)
+{
+ struct iphdr *ip, iph;
+ struct udphdr *udp;
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = iov_len,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0
+ };
+ int ret, iphl;
+ struct sockaddr_ll sll;
+ socklen_t sllen = sizeof(sll);
+
+ sll.sll_ifindex = dev->ifindex;
+ msg.msg_name = &sll;
+ msg.msg_namelen = sllen;
+
+ ret = recvfrom(dev->pkt_fd, &iph, sizeof(struct iphdr),
+ MSG_PEEK, (struct sockaddr *)&sll, &sllen);
+ if (ret == -1)
+ return -1;
+
+ if (iph.ihl < 5 || iph.version != IPVERSION)
+ goto discard_pkt;
+
+ iphl = iph.ihl * 4;
+
+ ip = malloc(iphl + sizeof(struct udphdr));
+ if (!ip)
+ goto discard_pkt;
+
+ udp = (struct udphdr *)((char *)ip + iphl);
+
+ iov[0].iov_base = ip;
+ iov[0].iov_len = iphl + sizeof(struct udphdr);
+
+ ret = recvmsg(dev->pkt_fd, &msg, 0);
+ if (ret == -1)
+ goto free_pkt;
+
+ dprintf("<- bytes %d ", ret);
+
+ if (ip_checksum((uint16_t *) ip, ip->ihl) != 0)
+ goto free_pkt;
+
+ dprintf("\n ip src %s ", ntoa(ip->saddr));
+ dprintf("dst %s ", ntoa(ip->daddr));
+
+ if (ntohs(ip->tot_len) > ret || ip->protocol != IPPROTO_UDP)
+ goto free_pkt;
+
+ ret -= 4 * ip->ihl;
+
+ dprintf("\n udp src %d dst %d ", ntohs(udp->source),
+ ntohs(udp->dest));
+
+ if (udp->source != htons(cfg_remote_port) ||
+ udp->dest != htons(cfg_local_port))
+ goto free_pkt;
+
+ if (ntohs(udp->len) > ret)
+ goto free_pkt;
+
+ ret -= sizeof(struct udphdr);
+
+ free(ip);
+
+ return ret;
+
+free_pkt:
+ dprintf("freed\n");
+ free(ip);
+ return 0;
+
+discard_pkt:
+ dprintf("discarded\n");
+ packet_discard(dev);
+ return 0;
+}
diff --git a/usr/kinit/ipconfig/packet.h b/usr/kinit/ipconfig/packet.h
new file mode 100644
index 0000000..4367efe
--- /dev/null
+++ b/usr/kinit/ipconfig/packet.h
@@ -0,0 +1,12 @@
+#ifndef IPCONFIG_PACKET_H
+#define IPCONFIG_PACKET_H
+
+struct iovec;
+
+int packet_open(struct netdev *dev);
+void packet_close(struct netdev *dev);
+int packet_send(struct netdev *dev, struct iovec *iov, int iov_len);
+void packet_discard(struct netdev *dev);
+int packet_recv(struct netdev *dev, struct iovec *iov, int iov_len);
+
+#endif /* IPCONFIG_PACKET_H */
diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c
new file mode 100644
index 0000000..28d2953
--- /dev/null
+++ b/usr/kinit/kinit.c
@@ -0,0 +1,331 @@
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <limits.h>
+#include <ctype.h>
+#include <termios.h>
+
+#include "kinit.h"
+#include "ipconfig.h"
+#include "run-init.h"
+#include "resume.h"
+
+const char *progname = "kinit";
+int mnt_procfs;
+int mnt_sysfs;
+
+#ifdef DEBUG
+void dump_args(int argc, char *argv[])
+{
+ int i;
+
+ printf(" argc == %d\n", argc);
+
+ for (i = 0; i < argc; i++)
+ printf(" argv[%d]: \"%s\"\n", i, argv[i]);
+
+ if (argv[argc] != NULL)
+ printf(" argv[%d]: \"%s\" (SHOULD BE NULL)\n",
+ argc, argv[argc]);
+}
+#endif /* DEBUG */
+
+
+static int do_ipconfig(int argc, char *argv[])
+{
+ int i, a = 0;
+ char **args = alloca((argc + 3) * sizeof(char *));
+
+ if (!args)
+ return -1;
+
+ args[a++] = (char *)"IP-Config";
+ args[a++] = (char *)"-i";
+ args[a++] = (char *)"Linux kinit";
+
+ dprintf("Running ipconfig\n");
+
+ for (i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "ip=", 3) == 0 ||
+ strncmp(argv[i], "nfsaddrs=", 9) == 0) {
+ args[a++] = argv[i];
+ }
+ }
+
+ if (a > 1) {
+ args[a] = NULL;
+ dump_args(a, args);
+ return ipconfig_main(a, args);
+ }
+
+ return 0;
+}
+
+static int split_cmdline(int cmdcmax, char *cmdv[], char *argv0,
+ char *cmdlines[], char *args[])
+{
+ int was_space;
+ char c, *p;
+ int vmax = cmdcmax;
+ int v = 1;
+ int space;
+
+ if (cmdv)
+ cmdv[0] = argv0;
+
+ /* First, add the parsable command lines */
+
+ while (*cmdlines) {
+ p = *cmdlines++;
+ was_space = 1;
+ while (v < vmax) {
+ c = *p;
+ space = isspace(c);
+ if ((space || !c) && !was_space) {
+ if (cmdv)
+ *p = '\0';
+ v++;
+ } else if (was_space) {
+ if (cmdv)
+ cmdv[v] = p;
+ }
+
+ if (!c)
+ break;
+
+ was_space = space;
+ p++;
+ }
+ }
+
+ /* Second, add the explicit command line arguments */
+
+ while (*args && v < vmax) {
+ if (cmdv)
+ cmdv[v] = *args;
+ v++;
+ args++;
+ }
+
+ if (cmdv)
+ cmdv[v] = NULL;
+
+ return v;
+}
+
+static int mount_sys_fs(const char *check, const char *fsname,
+ const char *fstype)
+{
+ struct stat st;
+
+ if (stat(check, &st) == 0)
+ return 0;
+
+ mkdir(fsname, 0555);
+
+ if (mount("none", fsname, fstype, 0, NULL) == -1) {
+ fprintf(stderr, "%s: could not mount %s as %s\n",
+ progname, fsname, fstype);
+ return -1;
+ }
+
+ return 1;
+}
+
+static void check_path(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) == -1) {
+ if (errno != ENOENT) {
+ perror("stat");
+ exit(1);
+ }
+ if (mkdir(path, 0755) == -1) {
+ perror("mkdir");
+ exit(1);
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "%s: '%s' not a directory\n", progname, path);
+ exit(1);
+ }
+}
+
+static const char *find_init(const char *root, const char *user)
+{
+ const char *init_paths[] = {
+ "/sbin/init", "/bin/init", "/etc/init", "/bin/sh", NULL
+ };
+ const char **p;
+ const char *path;
+
+ if (chdir(root)) {
+ perror("chdir");
+ exit(1);
+ }
+
+ if (user)
+ dprintf("Checking for init: %s\n", user);
+
+ if (user && user[0] == '/' && !access(user+1, X_OK)) {
+ path = user;
+ } else {
+ for (p = init_paths; *p; p++) {
+ dprintf("Checking for init: %s\n", *p);
+ if (!access(*p+1, X_OK))
+ break;
+ }
+ path = *p;
+ }
+ chdir("/");
+ return path;
+}
+
+/* This is the argc and argv we pass to init */
+const char *init_path;
+int init_argc;
+char **init_argv;
+
+extern ssize_t readfile(const char *, char **);
+
+int main(int argc, char *argv[])
+{
+ char **cmdv, **args;
+ char *cmdlines[3];
+ int i;
+ const char *errmsg;
+ int ret = 0;
+ int cmdc;
+ int fd;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ srand48(now.tv_usec ^ (now.tv_sec << 24));
+
+ /* Default parameters for anything init-like we execute */
+ init_argc = argc;
+ init_argv = alloca((argc+1)*sizeof(char *));
+ memcpy(init_argv, argv, (argc+1)*sizeof(char *));
+
+ if ((fd = open("/dev/console", O_RDWR)) != -1) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+
+ mnt_procfs = mount_sys_fs("/proc/cmdline", "/proc", "proc") >= 0;
+ if (!mnt_procfs) {
+ ret = 1;
+ goto bail;
+ }
+
+ mnt_sysfs = mount_sys_fs("/sys/bus", "/sys", "sysfs") >= 0;
+ if (!mnt_sysfs) {
+ ret = 1;
+ goto bail;
+ }
+
+ /* Construct the effective kernel command line. The
+ effective kernel command line consists of /arch.cmd, if
+ it exists, /proc/cmdline, plus any arguments after an --
+ argument on the proper command line, in that order. */
+
+ ret = readfile("/arch.cmd", &cmdlines[0]);
+ if (ret < 0)
+ cmdlines[0] = "";
+
+ ret = readfile("/proc/cmdline", &cmdlines[1]);
+ if (ret < 0) {
+ fprintf(stderr, "%s: cannot read /proc/cmdline\n", progname);
+ ret = 1;
+ goto bail;
+ }
+
+ cmdlines[2] = NULL;
+
+ /* Find an -- argument, and if so append to the command line */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--")) {
+ i++;
+ break;
+ }
+ }
+ args = &argv[i]; /* Points either to first argument past -- or
+ to the final NULL */
+
+ /* Count the number of arguments */
+ cmdc = split_cmdline(INT_MAX, NULL, argv[0], cmdlines, args);
+
+ /* Actually generate the cmdline array */
+ cmdv = (char **)alloca((cmdc+1)*sizeof(char *));
+ if (split_cmdline(cmdc, cmdv, argv[0], cmdlines, args) != cmdc) {
+ ret = 1;
+ goto bail;
+ }
+
+ /* Debugging... */
+ dump_args(cmdc, cmdv);
+
+ /* Resume from suspend-to-disk, if appropriate */
+ /* If successful, does not return */
+ do_resume(cmdc, cmdv);
+
+ /* Initialize networking, if applicable */
+ do_ipconfig(cmdc, cmdv);
+
+ check_path("/root");
+ do_mounts(cmdc, cmdv);
+
+ if (mnt_procfs) {
+ umount2("/proc", 0);
+ mnt_procfs = 0;
+ }
+
+ if (mnt_sysfs) {
+ umount2("/sys", 0);
+ mnt_sysfs = 0;
+ }
+
+ init_path = find_init("/root", get_arg(cmdc, cmdv, "init="));
+ if (!init_path) {
+ fprintf(stderr, "%s: init not found!\n", progname);
+ ret = 2;
+ goto bail;
+ }
+
+ init_argv[0] = strrchr(init_path, '/') + 1;
+
+ errmsg = run_init("/root", "/dev/console",
+ get_arg(cmdc, cmdv, "drop_capabilities="), false,
+ false, init_path, init_argv);
+
+ /* If run_init returned, something went bad */
+ fprintf(stderr, "%s: %s: %s\n", progname, errmsg, strerror(errno));
+ ret = 2;
+ goto bail;
+
+bail:
+ if (mnt_procfs)
+ umount2("/proc", 0);
+
+ if (mnt_sysfs)
+ umount2("/sys", 0);
+
+ /*
+ * If we get here, something bad probably happened, and the kernel
+ * will most likely panic. Drain console output so the user can
+ * figure out what happened.
+ */
+ tcdrain(2);
+ tcdrain(1);
+
+ return ret;
+}
diff --git a/usr/kinit/kinit.h b/usr/kinit/kinit.h
new file mode 100644
index 0000000..ee006f4
--- /dev/null
+++ b/usr/kinit/kinit.h
@@ -0,0 +1,70 @@
+/*
+ * kinit/kinit.h
+ */
+
+#ifndef KINIT_H
+#define KINIT_H
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+int do_mounts(int argc, char *argv[]);
+int mount_nfs_root(int argc, char *argv[], int flags);
+int ramdisk_load(int argc, char *argv[]);
+void md_run(int argc, char *argv[]);
+const char *bdevname(dev_t dev);
+
+extern int mnt_procfs;
+extern int mnt_sysfs;
+
+extern int init_argc;
+extern char **init_argv;
+extern const char *progname;
+
+char *get_arg(int argc, char *argv[], const char *name);
+int get_flag(int argc, char *argv[], const char *name);
+
+int getintfile(const char *path, long *val);
+
+ssize_t readfile(const char *path, char **pptr);
+ssize_t freadfile(FILE *f, char **pptr);
+
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ * From the Linux kernel.
+ */
+#define min(x, y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x < _y ? _x : _y; })
+
+#define max(x, y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x > _y ? _x : _y; })
+
+
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
+#ifdef DEBUG
+void dump_args(int argc, char *argv[]);
+#else
+static inline void dump_args(int argc, char *argv[])
+{
+ (void)argc;
+ (void)argv;
+}
+#endif
+
+int drop_capabilities(const char *caps);
+
+#endif /* KINIT_H */
diff --git a/usr/kinit/name_to_dev.c b/usr/kinit/name_to_dev.c
new file mode 100644
index 0000000..c57b7ce
--- /dev/null
+++ b/usr/kinit/name_to_dev.c
@@ -0,0 +1,276 @@
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <inttypes.h>
+
+#include "do_mounts.h"
+#include "kinit.h"
+
+#define BUF_SZ 65536
+
+/* Find dev_t for e.g. "hda,NULL" or "hdb,2" */
+static dev_t try_name(char *name, int part)
+{
+ char path[BUF_SZ];
+ char buf[BUF_SZ];
+ int range;
+ unsigned int major_num, minor_num;
+ dev_t res;
+ char *s;
+ int len;
+ int fd;
+
+ /* read device number from /sys/block/.../dev */
+ snprintf(path, sizeof(path), "/sys/block/%s/dev", name);
+ fd = open(path, 0, 0);
+ if (fd < 0)
+ goto fail;
+ len = read(fd, buf, BUF_SZ);
+ close(fd);
+
+ if (len <= 0 || len == BUF_SZ || buf[len - 1] != '\n')
+ goto fail;
+ buf[len - 1] = '\0';
+ major_num = strtoul(buf, &s, 10);
+ if (*s != ':')
+ goto fail;
+ minor_num = strtoul(s + 1, &s, 10);
+ if (*s)
+ goto fail;
+ res = makedev(major_num, minor_num);
+
+ /* if it's there and we are not looking for a partition - that's it */
+ if (!part)
+ return res;
+
+ /* otherwise read range from .../range */
+ snprintf(path, sizeof(path), "/sys/block/%s/range", name);
+ fd = open(path, 0, 0);
+ if (fd < 0)
+ goto fail;
+ len = read(fd, buf, 32);
+ close(fd);
+ if (len <= 0 || len == 32 || buf[len - 1] != '\n')
+ goto fail;
+ buf[len - 1] = '\0';
+ range = strtoul(buf, &s, 10);
+ if (*s)
+ goto fail;
+
+ /* if partition is within range - we got it */
+ if (part < range) {
+ dprintf("kinit: try_name %s,%d = %s\n", name, part,
+ bdevname(res + part));
+ return res + part;
+ }
+
+fail:
+ return (dev_t) 0;
+}
+
+/*
+ * Find dev_t for a block device based on the provided GPT partlabel.
+ * The partlabel to block device mapping is found by scanning all
+ * the entries in /sys/dev/block/, opening the uevent file and picking
+ * the device where the PARTNAME= entry matches partlabel.
+ */
+static dev_t partlabel_to_dev_t(const char *plabel)
+{
+ char path[BUF_SZ];
+ DIR *dir;
+ FILE *fp;
+ struct dirent *dent;
+ char *ret;
+ char line[BUF_SZ];
+ int match_label, major, minor;
+
+ dir = opendir("/sys/dev/block");
+ if (!dir) {
+ dprintf(stderr, "%s: error %i (%s) opening /sys/dev/block\n",
+ __func__, errno, strerror(errno));
+ goto fail;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ if (!strncmp(dent->d_name, ".", 1))
+ continue;
+ snprintf(path, sizeof(path), "/sys/dev/block/%s/uevent",
+ dent->d_name);
+
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ dprintf(stderr, "kinit %s: error %i (%s) opening %s",
+ __func__, errno, strerror(errno), path);
+ continue;
+ }
+
+ major = 0;
+ minor = 0;
+ match_label = 0;
+ while (!feof(fp)) {
+ ret = fgets(line, sizeof(line), fp);
+ if (ret == NULL)
+ continue;
+ if (!strncmp(line, "MAJOR=", 6))
+ major = atoi(line+6);
+ if (!strncmp(line, "MINOR=", 6))
+ minor = atoi(line+6);
+ if (!strncmp(line, "PARTNAME=", 9)) {
+ line[strcspn(line, "\n")] = 0;
+ if (!strncmp(line + 9, plabel, sizeof(line)-9))
+ match_label = 1;
+ }
+ if (match_label && major && minor) {
+ fclose(fp);
+ closedir(dir);
+ return makedev(major, minor);
+ }
+ }
+ fclose(fp);
+ }
+ closedir(dir);
+
+fail:
+ return (dev_t) 0;
+}
+
+/*
+ * Convert a name into device number. We accept the following variants:
+ *
+ * 1) device number in hexadecimal represents itself
+ * 2) device number in major:minor decimal represents itself
+ * 3) /dev/nfs represents Root_NFS
+ * 4) /dev/<disk_name> represents the device number of disk
+ * 5) /dev/<disk_name><decimal> represents the device number
+ * of partition - device number of disk plus the partition number
+ * 6) /dev/<disk_name>p<decimal> - same as the above, that form is
+ * used when disk name of partitioned disk ends on a digit.
+ * 7) an actual block device node in the initramfs filesystem
+ * 8) PARTLABEL=<name> with name being the GPT partition label.
+ *
+ * If name doesn't have fall into the categories above, we return 0.
+ * Driverfs is used to check if something is a disk name - it has
+ * all known disks under bus/block/devices. If the disk name
+ * contains slashes, name of driverfs node has them replaced with
+ * dots. try_name() does the actual checks, assuming that driverfs
+ * is mounted on rootfs /sys.
+ */
+
+static inline dev_t name_to_dev_t_real(const char *name)
+{
+ char *p;
+ dev_t res = 0;
+ char *s;
+ int part;
+ struct stat st;
+ int len;
+ const char *devname;
+ char *cptr, *e1, *e2;
+ int major_num, minor_num;
+
+ /* Are we a multi root line? */
+ if (strchr(name, ','))
+ return Root_MULTI;
+
+ if (!strncmp(name, "PARTLABEL=", 10))
+ return partlabel_to_dev_t(name + 10);
+
+ if (name[0] == '/') {
+ devname = name;
+ } else {
+ char *dname = alloca(strlen(name) + 6);
+ sprintf(dname, "/dev/%s", name);
+ devname = dname;
+ }
+
+ if (!stat(devname, &st) && S_ISBLK(st.st_mode))
+ return st.st_rdev;
+
+ if (strncmp(name, "/dev/", 5)) {
+ cptr = strchr(devname+5, ':');
+ if (cptr && cptr[1] != '\0') {
+ /* Colon-separated decimal device number */
+ *cptr = '\0';
+ major_num = strtoul(devname+5, &e1, 10);
+ minor_num = strtoul(cptr+1, &e2, 10);
+ if (!*e1 && !*e2)
+ return makedev(major_num, minor_num);
+ *cptr = ':';
+ } else {
+ /* Hexadecimal device number */
+ res = (dev_t) strtoul(name, &p, 16);
+ if (!*p)
+ return res;
+ }
+ } else {
+ name += 5;
+ }
+
+ if (!strcmp(name, "nfs"))
+ return Root_NFS;
+
+ if (!strcmp(name, "ram")) /* /dev/ram - historic alias for /dev/ram0 */
+ return Root_RAM0;
+
+ if (!strncmp(name, "mtd", 3))
+ return Root_MTD;
+
+ len = strlen(name);
+ s = alloca(len + 1);
+ memcpy(s, name, len + 1);
+
+ for (p = s; *p; p++)
+ if (*p == '/')
+ *p = '!';
+ res = try_name(s, 0);
+ if (res)
+ return res;
+
+ while (p > s && isdigit(p[-1]))
+ p--;
+ if (p == s || !*p || *p == '0')
+ goto fail;
+ part = strtoul(p, NULL, 10);
+ *p = '\0';
+ res = try_name(s, part);
+ if (res)
+ return res;
+
+ if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
+ goto fail;
+ p[-1] = '\0';
+ res = try_name(s, part);
+ return res;
+
+fail:
+ return (dev_t) 0;
+}
+
+dev_t name_to_dev_t(const char *name)
+{
+ dev_t dev = name_to_dev_t_real(name);
+
+ dprintf("kinit: name_to_dev_t(%s) = %s\n", name, bdevname(dev));
+ return dev;
+}
+
+#ifdef TEST_NAMETODEV /* Standalone test */
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ name_to_dev_t(argv[i]);
+
+ return 0;
+}
+
+#endif
diff --git a/usr/kinit/nfsmount/Kbuild b/usr/kinit/nfsmount/Kbuild
new file mode 100644
index 0000000..5f34950
--- /dev/null
+++ b/usr/kinit/nfsmount/Kbuild
@@ -0,0 +1,31 @@
+#
+# kbuild file for nfsmount
+#
+
+static-y := static/nfsmount
+#FIXME - build is broken static-y := dummypmap
+shared-y := shared/nfsmount
+
+objs := main.o mount.o portmap.o dummypmap.o sunrpc.o
+
+# Create built-in.o with all .o files (used by kinit)
+lib-y := $(objs)
+
+# .o files used for executables
+static/nfsmount-y := $(objs)
+shared/nfsmount-y := $(objs)
+
+# dummypmap uses a single .o file (rename src file?)
+dummypmap-y := dummypmap_test.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+clean-dirs := static shared
+
+# Install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
diff --git a/usr/kinit/nfsmount/README.locking b/usr/kinit/nfsmount/README.locking
new file mode 100644
index 0000000..bf2e8e7
--- /dev/null
+++ b/usr/kinit/nfsmount/README.locking
@@ -0,0 +1,26 @@
+I have implemented portmap spoofing in klibc nfsmount (released as
+klibc-0.144) This is basically a vestigial portmap daemon which gets
+launched before the mount() call and then just records any
+transactions it gets to a file and sends back an affirmative reply.
+
+There are two ways to use it (this belongs in a README file, but it's
+too late at night right now):
+
+a) Set a fixed portnumber in /proc/sys/nfs/nlm_tcpport and
+/proc/sys/nfs/nlm_udpport before calling nfsmount; once the portmapper
+starts feed that fixed portnumber to pmap_set(8). In this case the
+pmap_file can be /dev/null.
+
+b) Allow the kernel to bind to any port and use the file produced by
+nfsroot to feed to pmap_set (it should be directly compatible); this
+means the file needs to be transferred to a place where the "real
+root" can find it before run-init.
+
+In either case, it is imperative that the real portmapper is launched
+before any program actually tries to create locks!
+
+To use it:
+
+ # We need the loopback device to be up before we do this!
+ ipconfig 127.0.0.1:::::lo:none
+ nfsroot -p pmap_file -o lock server:/pathname /realpath
diff --git a/usr/kinit/nfsmount/dummypmap.c b/usr/kinit/nfsmount/dummypmap.c
new file mode 100644
index 0000000..07210c5
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap.c
@@ -0,0 +1,281 @@
+/*
+ * Enough portmapper functionality that mount doesn't hang trying
+ * to start lockd. Enables nfsroot with locking functionality.
+ *
+ * Note: the kernel will only speak to the local portmapper
+ * using RPC over UDP.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "dummypmap.h"
+#include "sunrpc.h"
+
+extern const char *progname;
+
+struct portmap_args {
+ uint32_t program;
+ uint32_t version;
+ uint32_t proto;
+ uint32_t port;
+};
+
+struct portmap_call {
+ struct rpc_call rpc;
+ struct portmap_args args;
+};
+
+struct portmap_reply {
+ struct rpc_reply rpc;
+ uint32_t port;
+};
+
+static int bind_portmap(void)
+{
+ int sock = socket(PF_INET, SOCK_DGRAM, 0);
+ struct sockaddr_in sin;
+
+ if (sock < 0)
+ return -1;
+
+ memset(&sin, 0, sizeof sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
+ sin.sin_port = htons(RPC_PMAP_PORT);
+ if (bind(sock, (struct sockaddr *)&sin, sizeof sin) < 0) {
+ int err = errno;
+ close(sock);
+ errno = err;
+ return -1;
+ }
+
+ return sock;
+}
+
+static const char *protoname(uint32_t proto)
+{
+ switch (ntohl(proto)) {
+ case IPPROTO_TCP:
+ return "tcp";
+ case IPPROTO_UDP:
+ return "udp";
+ default:
+ return NULL;
+ }
+}
+
+static void *get_auth(struct rpc_auth *auth)
+{
+ switch (ntohl(auth->flavor)) {
+ case AUTH_NULL:
+ /* Fallthrough */
+ case AUTH_UNIX:
+ return (char *)&auth->body + ntohl(auth->len);
+ default:
+ return NULL;
+ }
+}
+
+static int check_unix_cred(struct rpc_auth *cred)
+{
+ uint32_t len;
+ int quad_len;
+ uint32_t node_name_len;
+ int quad_name_len;
+ uint32_t *base;
+ uint32_t *pos;
+ int ret = -1;
+
+ len = ntohl(cred->len);
+ quad_len = (len + 3) >> 2;
+ if (quad_len < 6)
+ /* Malformed creds */
+ goto out;
+
+ base = pos = cred->body;
+
+ /* Skip timestamp */
+ pos++;
+
+ /* Skip node name: only localhost can succeed. */
+ node_name_len = ntohl(*pos++);
+ quad_name_len = (node_name_len + 3) >> 2;
+ if (pos + quad_name_len + 3 > base + quad_len)
+ /* Malformed creds */
+ goto out;
+ pos += quad_name_len;
+
+ /* uid must be 0 */
+ if (*pos++ != 0)
+ goto out;
+
+ /* gid must be 0 */
+ if (*pos++ != 0)
+ goto out;
+
+ /* Skip remaining gids */
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static int check_cred(struct rpc_auth *cred)
+{
+ switch (ntohl(cred->flavor)) {
+ case AUTH_NULL:
+ return 0;
+ case AUTH_UNIX:
+ return check_unix_cred(cred);
+ default:
+ return -1;
+ }
+}
+
+static int check_vrf(struct rpc_auth *vrf)
+{
+ return (vrf->flavor == htonl(AUTH_NULL)) ? 0 : -1;
+}
+
+#define MAX_UDP_PACKET 65536
+
+static int dummy_portmap(int sock, FILE *portmap_file)
+{
+ enum { PAYLOAD_SIZE = MAX_UDP_PACKET + offsetof(struct rpc_header, udp) };
+ struct sockaddr_in sin;
+ int pktlen, addrlen;
+ union {
+ struct rpc_call rpc;
+ /* Max UDP packet size + unused TCP fragment size */
+ char payload[PAYLOAD_SIZE];
+ } pkt;
+ struct rpc_call *rpc = &pkt.rpc;
+ struct rpc_auth *cred;
+ struct rpc_auth *vrf;
+ struct portmap_args *args;
+ struct portmap_reply rply;
+
+ for (;;) {
+ addrlen = sizeof sin;
+ pktlen = recvfrom(sock, &rpc->hdr.udp, MAX_UDP_PACKET,
+ 0, (struct sockaddr *)&sin, &addrlen);
+
+ if (pktlen < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -1;
+ }
+
+ /* +4 to skip the TCP fragment header */
+ if (pktlen + 4 < sizeof(struct portmap_call))
+ continue; /* Bad packet */
+
+ if (rpc->hdr.udp.msg_type != htonl(RPC_CALL))
+ continue; /* Bad packet */
+
+ memset(&rply, 0, sizeof rply);
+
+ rply.rpc.hdr.udp.xid = rpc->hdr.udp.xid;
+ rply.rpc.hdr.udp.msg_type = htonl(RPC_REPLY);
+
+ cred = (struct rpc_auth *) &rpc->cred_flavor;
+ if (rpc->rpc_vers != htonl(2)) {
+ rply.rpc.reply_state = htonl(REPLY_DENIED);
+ /* state <- RPC_MISMATCH == 0 */
+ } else if (rpc->program != htonl(PORTMAP_PROGRAM)) {
+ rply.rpc.reply_state = htonl(PROG_UNAVAIL);
+ } else if (rpc->prog_vers != htonl(2)) {
+ rply.rpc.reply_state = htonl(PROG_MISMATCH);
+ } else if (!(vrf = get_auth(cred)) ||
+ (char *)vrf > ((char *)&rpc->hdr.udp + pktlen - 8 -
+ sizeof(*args)) ||
+ !(args = get_auth(vrf)) ||
+ (char *)args > ((char *)&rpc->hdr.udp + pktlen -
+ sizeof(*args)) ||
+ check_cred(cred) || check_vrf(vrf)) {
+ /* Can't deal with credentials data; the kernel
+ won't send them */
+ rply.rpc.reply_state = htonl(SYSTEM_ERR);
+ } else {
+ switch (ntohl(rpc->proc)) {
+ case PMAP_PROC_NULL:
+ break;
+ case PMAP_PROC_SET:
+ if (args->proto == htonl(IPPROTO_TCP) ||
+ args->proto == htonl(IPPROTO_UDP)) {
+ if (portmap_file)
+ fprintf(portmap_file,
+ "%u %u %s %u\n",
+ ntohl(args->program),
+ ntohl(args->version),
+ protoname(args->proto),
+ ntohl(args->port));
+ rply.port = htonl(1); /* TRUE = success */
+ }
+ break;
+ case PMAP_PROC_UNSET:
+ rply.port = htonl(1); /* TRUE = success */
+ break;
+ case PMAP_PROC_GETPORT:
+ break;
+ case PMAP_PROC_DUMP:
+ break;
+ default:
+ rply.rpc.reply_state = htonl(PROC_UNAVAIL);
+ break;
+ }
+ }
+
+ sendto(sock, &rply.rpc.hdr.udp, sizeof rply - 4, 0,
+ (struct sockaddr *)&sin, addrlen);
+ }
+}
+
+pid_t start_dummy_portmap(const char *file)
+{
+ FILE *portmap_filep;
+ int sock;
+ pid_t spoof_portmap;
+
+ portmap_filep = fopen(file, "w");
+ if (!portmap_filep) {
+ fprintf(stderr, "%s: cannot write portmap file: %s\n",
+ progname, file);
+ return -1;
+ }
+
+ sock = bind_portmap();
+ if (sock == -1) {
+ if (errno == EINVAL || errno == EADDRINUSE)
+ return 0; /* Assume not needed */
+ else {
+ fclose(portmap_filep);
+ fprintf(stderr, "%s: portmap spoofing failed\n",
+ progname);
+ return -1;
+ }
+ }
+
+ spoof_portmap = fork();
+ if (spoof_portmap == -1) {
+ fclose(portmap_filep);
+ fprintf(stderr, "%s: cannot fork\n", progname);
+ return -1;
+ } else if (spoof_portmap == 0) {
+ /* Child process */
+ dummy_portmap(sock, portmap_filep);
+ _exit(255); /* Error */
+ } else {
+ /* Parent process */
+ close(sock);
+ return spoof_portmap;
+ }
+}
diff --git a/usr/kinit/nfsmount/dummypmap.h b/usr/kinit/nfsmount/dummypmap.h
new file mode 100644
index 0000000..37650bf
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap.h
@@ -0,0 +1,11 @@
+/*
+ * Functions for the portmap spoofer
+ */
+
+#ifndef NFSMOUNT_DUMMYPORTMAP_H
+#define NFSMOUNT_DUMMYPORTMAP_H
+
+#include <unistd.h>
+pid_t start_dummy_portmap(const char *file);
+
+#endif /* NFSMOUNT_DUMMYPORTMAP_H */
diff --git a/usr/kinit/nfsmount/dummypmap_test.c b/usr/kinit/nfsmount/dummypmap_test.c
new file mode 100644
index 0000000..d81a141
--- /dev/null
+++ b/usr/kinit/nfsmount/dummypmap_test.c
@@ -0,0 +1,2 @@
+#define TEST
+#include "dummypmap.c"
diff --git a/usr/kinit/nfsmount/main.c b/usr/kinit/nfsmount/main.c
new file mode 100644
index 0000000..66969f4
--- /dev/null
+++ b/usr/kinit/nfsmount/main.c
@@ -0,0 +1,288 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <klibc/sysconfig.h> /* For _KLIBC_NO_MMU */
+
+#include <linux/nfs_mount.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+#include "dummypmap.h"
+
+const char *progname;
+static jmp_buf abort_buf;
+
+static struct nfs_mount_data mount_data = {
+ .version = NFS_MOUNT_VERSION,
+ .flags = NFS_MOUNT_NONLM | NFS_MOUNT_VER3 | NFS_MOUNT_TCP,
+ .rsize = 0, /* Server's choice */
+ .wsize = 0, /* Server's choice */
+ .timeo = 0, /* Kernel client's default */
+ .retrans = 3,
+ .acregmin = 3,
+ .acregmax = 60,
+ .acdirmin = 30,
+ .acdirmax = 60,
+ .namlen = NAME_MAX,
+};
+
+int nfs_port;
+int nfs_version;
+
+static struct int_opts {
+ char *name;
+ int *val;
+} int_opts[] = {
+ {"port", &nfs_port},
+ {"nfsvers", &nfs_version},
+ {"vers", &nfs_version},
+ {"rsize", &mount_data.rsize},
+ {"wsize", &mount_data.wsize},
+ {"timeo", &mount_data.timeo},
+ {"retrans", &mount_data.retrans},
+ {"acregmin", &mount_data.acregmin},
+ {"acregmax", &mount_data.acregmax},
+ {"acdirmin", &mount_data.acdirmin},
+ {"acdirmax", &mount_data.acdirmax},
+ {NULL, NULL}
+};
+
+static struct bool_opts {
+ char *name;
+ int and_mask;
+ int or_mask;
+} bool_opts[] = {
+ {"soft", ~NFS_MOUNT_SOFT, NFS_MOUNT_SOFT},
+ {"hard", ~NFS_MOUNT_SOFT, 0},
+ {"intr", ~NFS_MOUNT_INTR, NFS_MOUNT_INTR},
+ {"nointr", ~NFS_MOUNT_INTR, 0},
+ {"posix", ~NFS_MOUNT_POSIX, NFS_MOUNT_POSIX},
+ {"noposix", ~NFS_MOUNT_POSIX, 0},
+ {"cto", ~NFS_MOUNT_NOCTO, 0},
+ {"nocto", ~NFS_MOUNT_NOCTO, NFS_MOUNT_NOCTO},
+ {"ac", ~NFS_MOUNT_NOAC, 0},
+ {"noac", ~NFS_MOUNT_NOAC, NFS_MOUNT_NOAC},
+ {"lock", ~NFS_MOUNT_NONLM, 0},
+ {"nolock", ~NFS_MOUNT_NONLM, NFS_MOUNT_NONLM},
+ {"acl", ~NFS_MOUNT_NOACL, 0},
+ {"noacl", ~NFS_MOUNT_NOACL, NFS_MOUNT_NOACL},
+ {"v2", ~NFS_MOUNT_VER3, 0},
+ {"v3", ~NFS_MOUNT_VER3, NFS_MOUNT_VER3},
+ {"udp", ~NFS_MOUNT_TCP, 0},
+ {"tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP},
+ {"broken_suid", ~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID},
+ {"ro", ~NFS_MOUNT_KLIBC_RONLY, NFS_MOUNT_KLIBC_RONLY},
+ {"rw", ~NFS_MOUNT_KLIBC_RONLY, 0},
+ {NULL, 0, 0}
+};
+
+static int parse_int(const char *val, const char *ctx)
+{
+ char *end;
+ int ret;
+
+ ret = (int)strtoul(val, &end, 0);
+ if (*val == '\0' || *end != '\0') {
+ fprintf(stderr, "%s: invalid value for %s\n", val, ctx);
+ longjmp(abort_buf, 1);
+ }
+ return ret;
+}
+
+static void parse_opts(char *opts)
+{
+ char *cp, *val;
+
+ while ((cp = strsep(&opts, ",")) != NULL) {
+ if (*cp == '\0')
+ continue;
+ val = strchr(cp, '=');
+ if (val != NULL) {
+ struct int_opts *opts = int_opts;
+ *val++ = '\0';
+ while (opts->name && strcmp(opts->name, cp) != 0)
+ opts++;
+ if (opts->name)
+ *(opts->val) = parse_int(val, opts->name);
+ else {
+ fprintf(stderr, "%s: bad option '%s'\n",
+ progname, cp);
+ longjmp(abort_buf, 1);
+ }
+ } else {
+ struct bool_opts *opts = bool_opts;
+ while (opts->name && strcmp(opts->name, cp) != 0)
+ opts++;
+ if (opts->name) {
+ mount_data.flags &= opts->and_mask;
+ mount_data.flags |= opts->or_mask;
+ } else {
+ fprintf(stderr, "%s: bad option '%s'\n",
+ progname, cp);
+ longjmp(abort_buf, 1);
+ }
+ }
+ }
+ /* If new-style options "nfsvers=" or "vers=" are passed, override
+ old "v2" and "v3" options */
+ if (nfs_version != 0) {
+ switch (nfs_version) {
+ case 2:
+ mount_data.flags &= ~NFS_MOUNT_VER3;
+ break;
+ case 3:
+ mount_data.flags |= NFS_MOUNT_VER3;
+ break;
+ default:
+ fprintf(stderr, "%s: bad NFS version '%d'\n",
+ progname, nfs_version);
+ longjmp(abort_buf, 1);
+ }
+ }
+}
+
+static uint32_t parse_addr(const char *ip)
+{
+ struct in_addr in;
+ if (inet_aton(ip, &in) == 0) {
+ fprintf(stderr, "%s: can't parse IP address '%s'\n",
+ progname, ip);
+ longjmp(abort_buf, 1);
+ }
+ return in.s_addr;
+}
+
+static void check_path(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) == -1) {
+ perror("stat");
+ longjmp(abort_buf, 1);
+ } else if (!S_ISDIR(st.st_mode)) {
+ fprintf(stderr, "%s: '%s' not a directory\n", progname, path);
+ longjmp(abort_buf, 1);
+ }
+}
+
+int main(int argc, char *argv[])
+ __attribute__ ((weak, alias("nfsmount_main")));
+
+int nfsmount_main(int argc, char *argv[])
+{
+ uint32_t server;
+ char *rem_name;
+ char *rem_path;
+ char *hostname;
+ char *path;
+ int c;
+ const char *portmap_file;
+ pid_t spoof_portmap;
+ int err, ret;
+
+ if ((err = setjmp(abort_buf)))
+ return err;
+
+ /* Set these here to avoid longjmp warning */
+ portmap_file = NULL;
+ spoof_portmap = 0;
+ server = 0;
+
+ /* If progname is set we're invoked from another program */
+ if (!progname) {
+ struct timeval now;
+ progname = argv[0];
+ gettimeofday(&now, NULL);
+ srand48(now.tv_usec ^ (now.tv_sec << 24));
+ }
+
+ while ((c = getopt(argc, argv, "o:p:")) != EOF) {
+ switch (c) {
+ case 'o':
+ parse_opts(optarg);
+ break;
+ case 'p':
+ portmap_file = optarg;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ return 1;
+ }
+ }
+
+ if (optind == argc) {
+ fprintf(stderr, "%s: need a path\n", progname);
+ return 1;
+ }
+
+ hostname = rem_path = argv[optind];
+
+ rem_name = strdup(rem_path);
+ if (rem_name == NULL) {
+ perror("strdup");
+ return 1;
+ }
+
+ rem_path = strchr(rem_path, ':');
+ if (rem_path == NULL) {
+ fprintf(stderr, "%s: need a server\n", progname);
+ free(rem_name);
+ return 1;
+ }
+
+ *rem_path++ = '\0';
+
+ if (*rem_path != '/') {
+ fprintf(stderr, "%s: need a path\n", progname);
+ free(rem_name);
+ return 1;
+ }
+
+ server = parse_addr(hostname);
+
+ if (optind <= argc - 2)
+ path = argv[optind + 1];
+ else
+ path = "/nfs_root";
+
+ check_path(path);
+
+#if !_KLIBC_NO_MMU
+ /* Note: uClinux can't fork(), so the spoof portmapper is not
+ available on uClinux. */
+ if (portmap_file)
+ spoof_portmap = start_dummy_portmap(portmap_file);
+
+ if (spoof_portmap == -1) {
+ free(rem_name);
+ return 1;
+ }
+#endif
+
+ ret = 0;
+ if (nfs_mount(rem_name, hostname, server, rem_path, path,
+ &mount_data) != 0)
+ ret = 1;
+
+ /* If we set up the spoofer, tear it down now */
+ if (spoof_portmap) {
+ kill(spoof_portmap, SIGTERM);
+ while (waitpid(spoof_portmap, NULL, 0) == -1
+ && errno == EINTR)
+ ;
+ }
+
+ free(rem_name);
+
+ return ret;
+}
diff --git a/usr/kinit/nfsmount/mount.c b/usr/kinit/nfsmount/mount.c
new file mode 100644
index 0000000..ae48354
--- /dev/null
+++ b/usr/kinit/nfsmount/mount.c
@@ -0,0 +1,347 @@
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <linux/nfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+static uint32_t mount_port;
+
+struct mount_call {
+ struct rpc_call rpc;
+ uint32_t path_len;
+ char path[0];
+};
+
+/*
+ * The following structure is the NFS v3 on-the-wire file handle,
+ * as defined in rfc1813.
+ * This differs from the structure used by the kernel,
+ * defined in <linux/nfh3.h>: rfc has a long in network order,
+ * kernel has a short in native order.
+ * Both kernel and rfc use the name nfs_fh; kernel name is
+ * visible to user apps in some versions of libc.
+ * Use different name to avoid clashes.
+ */
+#define NFS_MAXFHSIZE_WIRE 64
+struct nfs_fh_wire {
+ uint32_t size;
+ char data[NFS_MAXFHSIZE_WIRE];
+} __attribute__ ((packed, aligned(4)));
+
+struct mount_reply {
+ struct rpc_reply reply;
+ uint32_t status;
+ struct nfs_fh_wire fh;
+} __attribute__ ((packed, aligned(4)));
+
+#define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(uint32_t))
+
+static int get_ports(uint32_t server, const struct nfs_mount_data *data)
+{
+ uint32_t nfs_ver, mount_ver;
+ uint32_t proto;
+
+ if (data->flags & NFS_MOUNT_VER3) {
+ nfs_ver = NFS3_VERSION;
+ mount_ver = NFS_MNT3_VERSION;
+ } else {
+ nfs_ver = NFS2_VERSION;
+ mount_ver = NFS_MNT_VERSION;
+ }
+
+ proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
+
+ if (nfs_port == 0) {
+ nfs_port = portmap(server, NFS_PROGRAM, nfs_ver, proto);
+ if (nfs_port == 0) {
+ if (proto == IPPROTO_TCP) {
+ struct in_addr addr = { server };
+ fprintf(stderr, "NFS over TCP not "
+ "available from %s\n", inet_ntoa(addr));
+ return -1;
+ }
+ nfs_port = NFS_PORT;
+ }
+ }
+
+ if (mount_port == 0) {
+ mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver, proto);
+ if (mount_port == 0)
+ mount_port = MOUNT_PORT;
+ }
+ return 0;
+}
+
+static inline int pad_len(int len)
+{
+ return (len + 3) & ~3;
+}
+
+static inline void dump_params(uint32_t server,
+ const char *path,
+ const struct nfs_mount_data *data)
+{
+ (void)server;
+ (void)path;
+ (void)data;
+
+#ifdef DEBUG
+ struct in_addr addr = { server };
+
+ printf("NFS params:\n");
+ printf(" server = %s, path = \"%s\", ", inet_ntoa(addr), path);
+ printf("version = %d, proto = %s\n",
+ data->flags & NFS_MOUNT_VER3 ? 3 : 2,
+ (data->flags & NFS_MOUNT_TCP) ? "tcp" : "udp");
+ printf(" mount_port = %d, nfs_port = %d, flags = %08x\n",
+ mount_port, nfs_port, data->flags);
+ printf(" rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+ data->rsize, data->wsize, data->timeo, data->retrans);
+ printf(" acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+ data->acregmin, data->acregmax, data->acdirmin, data->acdirmax);
+ printf(" soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
+ (data->flags & NFS_MOUNT_SOFT) != 0,
+ (data->flags & NFS_MOUNT_INTR) != 0,
+ (data->flags & NFS_MOUNT_POSIX) != 0,
+ (data->flags & NFS_MOUNT_NOCTO) != 0,
+ (data->flags & NFS_MOUNT_NOAC) != 0);
+#endif
+}
+
+static inline void dump_fh(const char *data, int len)
+{
+ (void)data;
+ (void)len;
+
+#ifdef DEBUG
+ int i = 0;
+ int max = len - (len % 8);
+
+ printf("Root file handle: %d bytes\n", NFS2_FHSIZE);
+
+ while (i < max) {
+ int j;
+
+ printf(" %4d: ", i);
+ for (j = 0; j < 4; j++) {
+ printf("%02x %02x %02x %02x ",
+ data[i] & 0xff, data[i + 1] & 0xff,
+ data[i + 2] & 0xff, data[i + 3] & 0xff);
+ }
+ i += j;
+ printf("\n");
+ }
+#endif
+}
+
+static struct mount_reply mnt_reply;
+
+static int mount_call(uint32_t proc, uint32_t version,
+ const char *path, struct client *clnt)
+{
+ struct mount_call *mnt_call = NULL;
+ size_t path_len, call_len;
+ struct rpc rpc;
+ int ret = 0;
+
+ path_len = strlen(path);
+ call_len = sizeof(*mnt_call) + pad_len(path_len);
+
+ mnt_call = malloc(call_len);
+ if (mnt_call == NULL) {
+ perror("malloc");
+ goto bail;
+ }
+
+ memset(mnt_call, 0, sizeof(*mnt_call));
+
+ mnt_call->rpc.program = htonl(NFS_MNT_PROGRAM);
+ mnt_call->rpc.prog_vers = htonl(version);
+ mnt_call->rpc.proc = htonl(proc);
+ mnt_call->path_len = htonl(path_len);
+ memcpy(mnt_call->path, path, path_len);
+
+ rpc.call = (struct rpc_call *)mnt_call;
+ rpc.call_len = call_len;
+ rpc.reply = (struct rpc_reply *)&mnt_reply;
+ rpc.reply_len = sizeof(mnt_reply);
+
+ if (rpc_call(clnt, &rpc) < 0)
+ goto bail;
+
+ if (proc != MNTPROC_MNT)
+ goto done;
+
+ if (rpc.reply_len < MNT_REPLY_MINSIZE) {
+ fprintf(stderr, "incomplete reply: %zu < %zu\n",
+ rpc.reply_len, MNT_REPLY_MINSIZE);
+ goto bail;
+ }
+
+ if (mnt_reply.status != 0) {
+ fprintf(stderr, "mount call failed - server replied: %s.\n",
+ strerror(ntohl(mnt_reply.status)));
+ goto bail;
+ }
+
+ goto done;
+
+bail:
+ ret = -1;
+
+done:
+ if (mnt_call)
+ free(mnt_call);
+
+ return ret;
+}
+
+static int mount_v2(const char *path,
+ struct nfs_mount_data *data, struct client *clnt)
+{
+ int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);
+
+ if (ret == 0) {
+ dump_fh((const char *)&mnt_reply.fh, NFS2_FHSIZE);
+
+ data->root.size = NFS_FHSIZE;
+ memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);
+ memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);
+ }
+
+ return ret;
+}
+
+static inline int umount_v2(const char *path, struct client *clnt)
+{
+ return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);
+}
+
+static int mount_v3(const char *path,
+ struct nfs_mount_data *data, struct client *clnt)
+{
+ int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);
+
+ if (ret == 0) {
+ size_t fhsize = ntohl(mnt_reply.fh.size);
+
+ dump_fh((const char *)&mnt_reply.fh.data, fhsize);
+
+ memset(data->old_root.data, 0, NFS_FHSIZE);
+ memset(&data->root, 0, sizeof(data->root));
+ data->root.size = fhsize;
+ memcpy(&data->root.data, mnt_reply.fh.data, fhsize);
+ data->flags |= NFS_MOUNT_VER3;
+ }
+
+ return ret;
+}
+
+static inline int umount_v3(const char *path, struct client *clnt)
+{
+ return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);
+}
+
+int nfs_mount(const char *pathname, const char *hostname,
+ uint32_t server, const char *rem_path, const char *path,
+ struct nfs_mount_data *data)
+{
+ struct client *clnt = NULL;
+ struct sockaddr_in addr;
+ char mounted = 0;
+ int sock = -1;
+ int ret = 0;
+ int mountflags;
+
+ if (get_ports(server, data) != 0)
+ goto bail;
+
+ dump_params(server, rem_path, data);
+
+ if (data->flags & NFS_MOUNT_TCP)
+ clnt = tcp_client(server, mount_port, CLI_RESVPORT);
+ else
+ clnt = udp_client(server, mount_port, CLI_RESVPORT);
+
+ if (clnt == NULL)
+ goto bail;
+
+ if (data->flags & NFS_MOUNT_VER3)
+ ret = mount_v3(rem_path, data, clnt);
+ else
+ ret = mount_v2(rem_path, data, clnt);
+
+ if (ret == -1)
+ goto bail;
+ mounted = 1;
+
+ if (data->flags & NFS_MOUNT_TCP)
+ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ else
+ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ if (sock == -1) {
+ perror("socket");
+ goto bail;
+ }
+
+ if (bindresvport(sock, 0) == -1) {
+ perror("bindresvport");
+ goto bail;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = server;
+ addr.sin_port = htons(nfs_port);
+ memcpy(&data->addr, &addr, sizeof(data->addr));
+
+ strncpy(data->hostname, hostname, sizeof(data->hostname));
+
+ data->fd = sock;
+
+ mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;
+ data->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ ret = mount(pathname, path, "nfs", mountflags, data);
+
+ if (ret == -1) {
+ if (errno == ENODEV) {
+ fprintf(stderr, "mount: the kernel lacks NFS v%d "
+ "support\n",
+ (data->flags & NFS_MOUNT_VER3) ? 3 : 2);
+ } else {
+ perror("mount");
+ }
+ goto bail;
+ }
+
+ dprintf("Mounted %s on %s\n", pathname, path);
+
+ goto done;
+
+bail:
+ if (mounted) {
+ if (data->flags & NFS_MOUNT_VER3)
+ umount_v3(rem_path, clnt);
+ else
+ umount_v2(rem_path, clnt);
+ }
+
+ ret = -1;
+
+done:
+ if (clnt)
+ client_free(clnt);
+
+ if (sock != -1)
+ close(sock);
+
+ return ret;
+}
diff --git a/usr/kinit/nfsmount/nfsmount.h b/usr/kinit/nfsmount/nfsmount.h
new file mode 100644
index 0000000..7b28ded
--- /dev/null
+++ b/usr/kinit/nfsmount/nfsmount.h
@@ -0,0 +1,34 @@
+#ifndef NFSMOUNT_NFSMOUNT_H
+#define NFSMOUNT_NFSMOUNT_H
+
+#include <linux/nfs_mount.h>
+
+extern int nfs_port;
+
+extern int nfsmount_main(int argc, char *argv[]);
+int nfs_mount(const char *rem_name, const char *hostname,
+ uint32_t server, const char *rem_path,
+ const char *path, struct nfs_mount_data *data);
+
+enum nfs_proto {
+ v2 = 2,
+ v3,
+};
+
+/* masked with NFS_MOUNT_FLAGMASK before mount() call */
+#define NFS_MOUNT_KLIBC_RONLY 0x00010000U
+
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
+#ifndef MNTPROC_MNT
+#define MNTPROC_MNT 1
+#endif
+#ifndef MNTPROC_UMNT
+#define MNTPROC_UMNT 3
+#endif
+
+#endif /* NFSMOUNT_NFSMOUNT_H */
diff --git a/usr/kinit/nfsmount/portmap.c b/usr/kinit/nfsmount/portmap.c
new file mode 100644
index 0000000..0a3e2d0
--- /dev/null
+++ b/usr/kinit/nfsmount/portmap.c
@@ -0,0 +1,73 @@
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h> /* __constant_hton* */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+struct portmap_call {
+ struct rpc_call rpc;
+ uint32_t program;
+ uint32_t version;
+ uint32_t proto;
+ uint32_t port;
+};
+
+struct portmap_reply {
+ struct rpc_reply rpc;
+ uint32_t port;
+};
+
+static struct portmap_call call = {
+ .rpc = {
+ .program = __constant_htonl(RPC_PMAP_PROGRAM),
+ .prog_vers = __constant_htonl(RPC_PMAP_VERSION),
+ .proc = __constant_htonl(PMAP_PROC_GETPORT),
+ }
+};
+
+uint32_t portmap(uint32_t server, uint32_t program, uint32_t version, uint32_t proto)
+{
+ struct portmap_reply reply;
+ struct client *clnt;
+ struct rpc rpc;
+ uint32_t port = 0;
+
+ clnt = tcp_client(server, RPC_PMAP_PORT, 0);
+ if (clnt == NULL) {
+ clnt = udp_client(server, RPC_PMAP_PORT, 0);
+ if (clnt == NULL)
+ goto bail;
+ }
+
+ call.program = htonl(program);
+ call.version = htonl(version);
+ call.proto = htonl(proto);
+
+ rpc.call = (struct rpc_call *)&call;
+ rpc.call_len = sizeof(call);
+ rpc.reply = (struct rpc_reply *)&reply;
+ rpc.reply_len = sizeof(reply);
+
+ if (rpc_call(clnt, &rpc) < 0)
+ goto bail;
+
+ if (rpc.reply_len < sizeof(reply)) {
+ fprintf(stderr, "incomplete reply: %zu < %zu\n",
+ rpc.reply_len, sizeof(reply));
+ goto bail;
+ }
+
+ port = ntohl(reply.port);
+
+bail:
+ dprintf("Port for %d/%d[%s]: %d\n", program, version,
+ proto == IPPROTO_TCP ? "tcp" : "udp", port);
+
+ if (clnt)
+ client_free(clnt);
+
+ return port;
+}
diff --git a/usr/kinit/nfsmount/sunrpc.c b/usr/kinit/nfsmount/sunrpc.c
new file mode 100644
index 0000000..0a7fcf5
--- /dev/null
+++ b/usr/kinit/nfsmount/sunrpc.c
@@ -0,0 +1,252 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nfsmount.h"
+#include "sunrpc.h"
+
+/*
+ * The magic offset is needed here because RPC over TCP includes a
+ * field that RPC over UDP doesn't. Luvverly.
+ */
+static int rpc_do_reply(struct client *clnt, struct rpc *rpc, size_t off)
+{
+ int ret;
+
+ if ((ret = read(clnt->sock,
+ ((char *)rpc->reply) + off,
+ rpc->reply_len - off)) == -1) {
+ perror("read");
+ goto bail;
+ } else if (ret < sizeof(struct rpc_reply) - off) {
+ fprintf(stderr, "short read: %d < %zu\n", ret,
+ sizeof(struct rpc_reply) - off);
+ goto bail;
+ }
+ rpc->reply_len = ret + off;
+
+ if ((!off && !(ntohl(rpc->reply->hdr.frag_hdr) & LAST_FRAG)) ||
+ rpc->reply->hdr.udp.xid != rpc->call->hdr.udp.xid ||
+ rpc->reply->hdr.udp.msg_type != htonl(RPC_REPLY)) {
+ fprintf(stderr, "bad reply\n");
+ goto bail;
+ }
+
+ if (ntohl(rpc->reply->state) != REPLY_OK) {
+ fprintf(stderr, "rpc failed: %d\n", ntohl(rpc->reply->state));
+ goto bail;
+ }
+
+ ret = 0;
+ goto done;
+
+bail:
+ ret = -1;
+done:
+ return ret;
+}
+
+static void rpc_header(struct client *clnt, struct rpc *rpc)
+{
+ (void)clnt;
+
+ rpc->call->hdr.frag_hdr = htonl(LAST_FRAG | (rpc->call_len - 4));
+ rpc->call->hdr.udp.xid = lrand48();
+ rpc->call->hdr.udp.msg_type = htonl(RPC_CALL);
+ rpc->call->rpc_vers = htonl(2);
+}
+
+static int rpc_call_tcp(struct client *clnt, struct rpc *rpc)
+{
+ int ret;
+
+ rpc_header(clnt, rpc);
+
+ if ((ret = write(clnt->sock, rpc->call, rpc->call_len)) == -1) {
+ perror("write");
+ goto bail;
+ } else if (ret < rpc->call_len) {
+ fprintf(stderr, "short write: %d < %zu\n", ret, rpc->call_len);
+ goto bail;
+ }
+
+ ret = rpc_do_reply(clnt, rpc, 0);
+ goto done;
+
+ bail:
+ ret = -1;
+
+ done:
+ return ret;
+}
+
+static int rpc_call_udp(struct client *clnt, struct rpc *rpc)
+{
+#define NR_FDS 1
+#define TIMEOUT_MS 3000
+#define MAX_TRIES 100
+#define UDP_HDR_OFF (sizeof(struct rpc_header) - sizeof(struct rpc_udp_header))
+ struct pollfd fds[NR_FDS];
+ int ret = -1;
+ int i;
+
+ rpc_header(clnt, rpc);
+
+ fds[0].fd = clnt->sock;
+ fds[0].events = POLLRDNORM;
+
+ rpc->call_len -= UDP_HDR_OFF;
+
+ for (i = 0; i < MAX_TRIES; i++) {
+ int timeout_ms = TIMEOUT_MS + (lrand48() % (TIMEOUT_MS / 2));
+ if ((ret = write(clnt->sock,
+ ((char *)rpc->call) + UDP_HDR_OFF,
+ rpc->call_len)) == -1) {
+ perror("write");
+ goto bail;
+ } else if (ret < rpc->call_len) {
+ fprintf(stderr, "short write: %d < %zu\n", ret,
+ rpc->call_len);
+ goto bail;
+ }
+ for (; i < MAX_TRIES; i++) {
+ if ((ret = poll(fds, NR_FDS, timeout_ms)) == -1) {
+ perror("poll");
+ goto bail;
+ }
+ if (ret == 0) {
+ dprintf("Timeout #%d\n", i + 1);
+ break;
+ }
+ if ((ret = rpc_do_reply(clnt, rpc, UDP_HDR_OFF)) == 0) {
+ goto done;
+ } else {
+ dprintf("Failed on try #%d - retrying\n",
+ i + 1);
+ }
+ }
+ }
+
+ bail:
+ ret = -1;
+
+ done:
+ return ret;
+}
+
+struct client *tcp_client(uint32_t server, uint16_t port, uint32_t flags)
+{
+ struct client *clnt = malloc(sizeof(*clnt));
+ struct sockaddr_in addr;
+ int sock;
+
+ if (clnt == NULL) {
+ perror("malloc");
+ goto bail;
+ }
+
+ memset(clnt, 0, sizeof(*clnt));
+
+ if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ perror("socket");
+ goto bail;
+ }
+
+ if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
+ perror("bindresvport");
+ goto bail;
+ }
+
+ clnt->sock = sock;
+ clnt->call_stub = rpc_call_tcp;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = server;
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ perror("connect");
+ goto bail;
+ }
+
+ goto done;
+ bail:
+ if (clnt) {
+ free(clnt);
+ clnt = NULL;
+ }
+ done:
+ return clnt;
+}
+
+struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags)
+{
+ struct client *clnt = malloc(sizeof(*clnt));
+ struct sockaddr_in addr;
+ int sock;
+
+ if (clnt == NULL) {
+ perror("malloc");
+ goto bail;
+ }
+
+ memset(clnt, 0, sizeof(*clnt));
+
+ if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
+ perror("socket");
+ goto bail;
+ }
+
+ if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
+ perror("bindresvport");
+ goto bail;
+ } else {
+ struct sockaddr_in me;
+
+ me.sin_family = AF_INET;
+ me.sin_port = 0;
+ me.sin_addr.s_addr = INADDR_ANY;
+
+ if (0 && bind(sock, (struct sockaddr *)&me, sizeof(me)) == -1) {
+ perror("bind");
+ goto bail;
+ }
+ }
+
+ clnt->sock = sock;
+ clnt->call_stub = rpc_call_udp;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = server;
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ perror("connect");
+ goto bail;
+ }
+
+ goto done;
+ bail:
+ if (clnt) {
+ free(clnt);
+ clnt = NULL;
+ }
+ done:
+ return clnt;
+}
+
+void client_free(struct client *c)
+{
+ if (c->sock != -1)
+ close(c->sock);
+ free(c);
+}
+
+int rpc_call(struct client *client, struct rpc *rpc)
+{
+ return client->call_stub(client, rpc);
+}
diff --git a/usr/kinit/nfsmount/sunrpc.h b/usr/kinit/nfsmount/sunrpc.h
new file mode 100644
index 0000000..1bcfeea
--- /dev/null
+++ b/usr/kinit/nfsmount/sunrpc.h
@@ -0,0 +1,110 @@
+/*
+ * open-coded SunRPC structures
+ */
+#ifndef NFSMOUNT_SUNRPC_H
+#define NFSMOUNT_SUNRPC_H
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+#define SUNRPC_PORT 111
+#define MOUNT_PORT 627
+
+#define RPC_CALL 0
+#define RPC_REPLY 1
+
+#define PORTMAP_PROGRAM 100000
+#define NLM_PROGRAM 100021
+
+#define RPC_PMAP_PROGRAM 100000
+#define RPC_PMAP_VERSION 2
+#define RPC_PMAP_PORT 111
+
+#define PMAP_PROC_NULL 0
+#define PMAP_PROC_SET 1
+#define PMAP_PROC_UNSET 2
+#define PMAP_PROC_GETPORT 3
+#define PMAP_PROC_DUMP 4
+
+#define LAST_FRAG 0x80000000
+
+#define REPLY_OK 0
+#define REPLY_DENIED 1
+
+#define SUCCESS 0
+#define PROG_UNAVAIL 1
+#define PROG_MISMATCH 2
+#define PROC_UNAVAIL 3
+#define GARBAGE_ARGS 4
+#define SYSTEM_ERR 5
+
+enum {
+ AUTH_NULL,
+ AUTH_UNIX,
+};
+
+struct rpc_auth {
+ uint32_t flavor;
+ uint32_t len;
+ uint32_t body[];
+};
+
+struct rpc_udp_header {
+ uint32_t xid;
+ uint32_t msg_type;
+};
+
+struct rpc_header {
+ uint32_t frag_hdr;
+ struct rpc_udp_header udp;
+};
+
+struct rpc_call {
+ struct rpc_header hdr;
+ uint32_t rpc_vers;
+
+ uint32_t program;
+ uint32_t prog_vers;
+ uint32_t proc;
+ uint32_t cred_flavor;
+
+ uint32_t cred_len;
+ uint32_t vrf_flavor;
+ uint32_t vrf_len;
+};
+
+struct rpc_reply {
+ struct rpc_header hdr;
+ uint32_t reply_state;
+ uint32_t vrf_flavor;
+ uint32_t vrf_len;
+ uint32_t state;
+};
+
+struct rpc {
+ struct rpc_call *call;
+ size_t call_len;
+ struct rpc_reply *reply;
+ size_t reply_len;
+};
+
+struct client;
+
+typedef int (*call_stub) (struct client *, struct rpc *);
+
+struct client {
+ int sock;
+ call_stub call_stub;
+};
+
+#define CLI_RESVPORT 00000001
+
+struct client *tcp_client(uint32_t server, uint16_t port, uint32_t flags);
+struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags);
+void client_free(struct client *client);
+
+int rpc_call(struct client *client, struct rpc *rpc);
+
+uint32_t portmap(uint32_t server, uint32_t program, uint32_t version, uint32_t proto);
+
+#endif /* NFSMOUNT_SUNRPC_H */
diff --git a/usr/kinit/nfsroot.c b/usr/kinit/nfsroot.c
new file mode 100644
index 0000000..3b80773
--- /dev/null
+++ b/usr/kinit/nfsroot.c
@@ -0,0 +1,111 @@
+#include <arpa/inet.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "kinit.h"
+#include "netdev.h"
+#include "nfsmount.h"
+
+static char *sub_client(__u32 client, char *path, size_t len)
+{
+ struct in_addr addr = { client };
+ char buf[len];
+
+ if (strstr(path, "%s") != NULL) {
+ if (client == INADDR_NONE) {
+ fprintf(stderr, "Root-NFS: no client address\n");
+ exit(1);
+ }
+
+ snprintf(buf, len, path, inet_ntoa(addr));
+ strcpy(path, buf);
+ }
+
+ return path;
+}
+
+#define NFS_ARGC 6
+#define MOUNT_POINT "/root"
+
+int mount_nfs_root(int argc, char *argv[], int flags)
+{
+ (void)flags; /* FIXME - don't ignore this */
+
+ struct in_addr addr = { INADDR_NONE };
+ __u32 client = INADDR_NONE;
+ const int len = 1024;
+ struct netdev *dev;
+ char *mtpt = MOUNT_POINT;
+ char *path = NULL;
+ char *dev_bootpath = NULL;
+ char root[len];
+ char *x, *opts;
+ int ret = 0;
+ int a = 1;
+ char *nfs_argv[NFS_ARGC + 1] = { "NFS-Mount" };
+
+ for (dev = ifaces; dev; dev = dev->next) {
+ if (dev->ip_server != INADDR_NONE &&
+ dev->ip_server != INADDR_ANY) {
+ addr.s_addr = dev->ip_server;
+ client = dev->ip_addr;
+ dev_bootpath = dev->bootpath;
+ break;
+ }
+ if (dev->ip_addr != INADDR_NONE && dev->ip_addr != INADDR_ANY)
+ client = dev->ip_addr;
+ }
+
+ /*
+ * if the "nfsroot" option is set then it overrides
+ * bootpath supplied by the boot server.
+ */
+ if ((path = get_arg(argc, argv, "nfsroot=")) == NULL) {
+ if ((path = dev_bootpath) == NULL || path[0] == '\0')
+ /* no path - set a default */
+ path = (char *)"/tftpboot/%s";
+ } else if (dev_bootpath && dev_bootpath[0] != '\0')
+ fprintf(stderr,
+ "nfsroot=%s overrides boot server bootpath %s\n",
+ path, dev_bootpath);
+
+ if ((opts = strchr(path, ',')) != NULL) {
+ *opts++ = '\0';
+ nfs_argv[a++] = (char *)"-o";
+ nfs_argv[a++] = opts;
+ }
+
+ if ((x = strchr(path, ':')) == NULL) {
+ if (addr.s_addr == INADDR_NONE) {
+ fprintf(stderr, "Root-NFS: no server defined\n");
+ exit(1);
+ }
+
+ snprintf(root, len, "%s:%s", inet_ntoa(addr), path);
+ } else {
+ strcpy(root, path);
+ }
+
+ nfs_argv[a++] = sub_client(client, root, len);
+
+ dprintf("NFS-Root: mounting %s on %s with options \"%s\"\n",
+ nfs_argv[a-1], mtpt, opts ? opts : "");
+
+ nfs_argv[a++] = mtpt;
+ nfs_argv[a] = NULL;
+ assert(a <= NFS_ARGC);
+
+ dump_args(a, nfs_argv);
+
+ if ((ret = nfsmount_main(a, nfs_argv)) != 0) {
+ ret = -1;
+ goto done;
+ }
+
+done:
+ return ret;
+}
diff --git a/usr/kinit/ramdisk_load.c b/usr/kinit/ramdisk_load.c
new file mode 100644
index 0000000..e3e15d8
--- /dev/null
+++ b/usr/kinit/ramdisk_load.c
@@ -0,0 +1,281 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+#include <linux/cdrom.h>
+#include <linux/fd.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+#include "fstype.h"
+#include "zlib.h"
+
+#define BUF_SZ 65536
+
+static void wait_for_key(void)
+{
+ /* Wait until the user presses Enter */
+ while (getchar() != '\n')
+ ;
+}
+
+static int change_disk(const char *devpath, int rfd, int disk)
+{
+ /* Try to eject and/or quiesce the device */
+ sync();
+ if (ioctl(rfd, FDEJECT, 0)) {
+ if (errno == ENOTTY) {
+ /* Not a floppy */
+ ioctl(rfd, CDROMEJECT, 0);
+ } else {
+ /* Non-ejectable floppy */
+ ioctl(rfd, FDRESET, (void *)FD_RESET_IF_NEEDED);
+ }
+ }
+ close(rfd);
+
+ fprintf(stderr,
+ "\nPlease insert disk %d for ramdisk and press Enter...", disk);
+ wait_for_key();
+
+ return open(devpath, O_RDONLY);
+}
+
+#ifdef CONFIG_KLIBC_ZLIB
+/* Also used in initrd.c */
+int load_ramdisk_compressed(const char *devpath, FILE * wfd,
+ off_t ramdisk_start)
+{
+ int rfd = -1;
+ unsigned long long ramdisk_size, ramdisk_left;
+ int disk = 1;
+ ssize_t bytes;
+ int rv;
+ unsigned char in_buf[BUF_SZ], out_buf[BUF_SZ];
+ z_stream zs;
+
+ zs.zalloc = Z_NULL; /* Use malloc() */
+ zs.zfree = Z_NULL; /* Use free() */
+ zs.next_in = Z_NULL; /* No data read yet */
+ zs.avail_in = 0;
+ zs.next_out = out_buf;
+ zs.avail_out = BUF_SZ;
+
+ if (inflateInit2(&zs, 32 + 15) != Z_OK)
+ goto err1;
+
+ rfd = open(devpath, O_RDONLY);
+ if (rfd < 0)
+ goto err2;
+
+ /* Set to the size of the medium, or "infinite" */
+ if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+ ramdisk_size = ~0ULL;
+
+ do {
+ /* Purge the output preferentially over reading new
+ input, so we don't end up overrunning the input by
+ accident and demanding a new disk which doesn't
+ exist... */
+ if (zs.avail_out == 0) {
+ _fwrite(out_buf, BUF_SZ, wfd);
+ zs.next_out = out_buf;
+ zs.avail_out = BUF_SZ;
+ } else if (zs.avail_in == 0) {
+ if (ramdisk_start >= ramdisk_size) {
+ rfd = change_disk(devpath, rfd, ++disk);
+ if (rfd < 0)
+ goto err2;
+
+ if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+ ramdisk_size = ~0ULL;
+ ramdisk_start = 0;
+ dprintf("New size = %llu\n", ramdisk_size);
+ }
+ do {
+ ramdisk_left = ramdisk_size - ramdisk_start;
+ bytes = min(ramdisk_left,
+ (unsigned long long)BUF_SZ);
+ bytes = pread(rfd, in_buf, bytes,
+ ramdisk_start);
+ } while (bytes == -1 && errno == EINTR);
+ if (bytes <= 0)
+ goto err2;
+ ramdisk_start += bytes;
+ zs.next_in = in_buf;
+ zs.avail_in = bytes;
+
+ /* Print dots if we're reading from a real block device */
+ if (ramdisk_size != ~0ULL)
+ putc('.', stderr);
+ }
+ rv = inflate(&zs, Z_SYNC_FLUSH);
+ } while (rv == Z_OK || rv == Z_BUF_ERROR);
+
+ dprintf("kinit: inflate returned %d\n", rv);
+
+ if (rv != Z_STREAM_END)
+ goto err2;
+
+ /* Write the last */
+ _fwrite(out_buf, BUF_SZ - zs.avail_out, wfd);
+ dprintf("kinit: writing %d bytes\n", BUF_SZ - zs.avail_out);
+
+ inflateEnd(&zs);
+ return 0;
+
+err2:
+ inflateEnd(&zs);
+err1:
+ return -1;
+}
+#else
+int load_ramdisk_compressed(const char *devpath, FILE * wfd,
+ off_t ramdisk_start)
+{
+ fprintf(stderr, "Compressed ramdisk not supported\n");
+ return -1;
+}
+#endif
+
+static int
+load_ramdisk_raw(const char *devpath, FILE * wfd, off_t ramdisk_start,
+ unsigned long long fssize)
+{
+ unsigned long long ramdisk_size, ramdisk_left;
+ int disk = 1;
+ ssize_t bytes;
+ unsigned char buf[BUF_SZ];
+ int rfd;
+
+ rfd = open(devpath, O_RDONLY);
+ if (rfd < 0)
+ return -1;
+
+ /* Set to the size of the medium, or "infinite" */
+ if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+ ramdisk_size = ~0ULL;
+
+ dprintf("start: %llu size: %llu fssize: %llu\n",
+ ramdisk_start, ramdisk_size, fssize);
+
+ while (fssize) {
+
+ if (ramdisk_start >= ramdisk_size) {
+ rfd = change_disk(devpath, rfd, ++disk);
+ if (rfd < 0)
+ return -1;
+
+ if (ioctl(rfd, BLKGETSIZE64, &ramdisk_size))
+ ramdisk_size = ~0ULL;
+ ramdisk_start = 0;
+ }
+
+ do {
+ ramdisk_left =
+ min(ramdisk_size - ramdisk_start, fssize);
+ bytes = min(ramdisk_left, (unsigned long long)BUF_SZ);
+ bytes = pread(rfd, buf, bytes, ramdisk_start);
+ } while (bytes == -1 && errno == EINTR);
+ if (bytes <= 0)
+ break;
+ _fwrite(buf, bytes, wfd);
+
+ ramdisk_start += bytes;
+ fssize -= bytes;
+
+ /* Print dots if we're reading from a real block device */
+ if (ramdisk_size != ~0ULL)
+ putc('.', stderr);
+ }
+
+ return !!fssize;
+}
+
+int ramdisk_load(int argc, char *argv[])
+{
+ const char *arg_prompt_ramdisk = get_arg(argc, argv, "prompt_ramdisk=");
+ const char *arg_ramdisk_blocksize =
+ get_arg(argc, argv, "ramdisk_blocksize=");
+ const char *arg_ramdisk_start = get_arg(argc, argv, "ramdisk_start=");
+ const char *arg_ramdisk_device = get_arg(argc, argv, "ramdisk_device=");
+
+ int prompt_ramdisk = arg_prompt_ramdisk ? atoi(arg_prompt_ramdisk) : 0;
+ int ramdisk_blocksize =
+ arg_ramdisk_blocksize ? atoi(arg_ramdisk_blocksize) : 512;
+ off_t ramdisk_start =
+ arg_ramdisk_start
+ ? strtoumax(arg_ramdisk_start, NULL, 10) * ramdisk_blocksize : 0;
+ const char *ramdisk_device =
+ arg_ramdisk_device ? arg_ramdisk_device : "/dev/fd0";
+
+ dev_t ramdisk_dev;
+ int rfd;
+ FILE *wfd;
+ const char *fstype;
+ unsigned long long fssize;
+ int is_gzip = 0;
+ int err;
+
+ if (prompt_ramdisk) {
+ fprintf(stderr,
+ "Please insert disk for ramdisk and press Enter...");
+ wait_for_key();
+ }
+
+ ramdisk_dev = name_to_dev_t(ramdisk_device);
+ if (!ramdisk_dev) {
+ fprintf(stderr,
+ "Failure loading ramdisk: unknown device: %s\n",
+ ramdisk_device);
+ return 0;
+ }
+
+ create_dev("/dev/rddev", ramdisk_dev);
+ create_dev("/dev/ram0", Root_RAM0);
+ rfd = open("/dev/rddev", O_RDONLY);
+ wfd = fopen("/dev/ram0", "w");
+
+ if (rfd < 0 || !wfd) {
+ perror("Could not open ramdisk device");
+ return 0;
+ }
+
+ /* Check filesystem type */
+ if (identify_fs(rfd, &fstype, &fssize, ramdisk_start) ||
+ (fssize == 0 && !(is_gzip = !strcmp(fstype, "gzip")))) {
+ fprintf(stderr,
+ "Failure loading ramdisk: unknown filesystem type\n");
+ close(rfd);
+ fclose(wfd);
+ return 0;
+ }
+
+ dprintf("kinit: ramdisk is %s, size %llu\n", fstype, fssize);
+
+ fprintf(stderr, "Loading ramdisk (%s) ...", is_gzip ? "gzip" : "raw");
+
+ close(rfd);
+
+ if (is_gzip)
+ err = load_ramdisk_compressed("/dev/rddev", wfd, ramdisk_start);
+ else
+ err = load_ramdisk_raw("/dev/rddev", wfd,
+ ramdisk_start, fssize);
+
+ fclose(wfd);
+
+ putc('\n', stderr);
+
+ if (err) {
+ perror("Failure loading ramdisk");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/usr/kinit/readfile.c b/usr/kinit/readfile.c
new file mode 100644
index 0000000..7a16b4a
--- /dev/null
+++ b/usr/kinit/readfile.c
@@ -0,0 +1,86 @@
+/*
+ * Read the entire contents of a file into malloc'd storage. This
+ * is mostly useful for things like /proc files where we can't just
+ * fstat() to get the length and then mmap().
+ *
+ * Returns the number of bytes read, or -1 on error.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "kinit.h"
+
+ssize_t freadfile(FILE *f, char **pp)
+{
+ size_t bs; /* Decent starting point... */
+ size_t bf; /* Bytes free */
+ size_t bu = 0; /* Bytes used */
+ char *buffer, *nb;
+ size_t rv;
+ int old_errno = errno;
+
+ bs = BUFSIZ; /* A guess as good as any */
+ bf = bs;
+ buffer = malloc(bs);
+
+ if (!buffer)
+ return -1;
+
+ for (;;) {
+ errno = 0;
+
+ while (bf && (rv = _fread(buffer + bu, bf, f))) {
+ bu += rv;
+ bf -= rv;
+ }
+
+ if (errno && errno != EINTR && errno != EAGAIN) {
+ /* error */
+ free(buffer);
+ return -1;
+ }
+
+ if (bf) {
+ /* Hit EOF, no error */
+
+ /* Try to free superfluous memory */
+ if ((nb = realloc(buffer, bu + 1)))
+ buffer = nb;
+
+ /* Null-terminate result for good measure */
+ buffer[bu] = '\0';
+
+ *pp = buffer;
+ errno = old_errno;
+ return bu;
+ }
+
+ /* Double the size of the buffer */
+ bf += bs;
+ bs += bs;
+ if (!(nb = realloc(buffer, bs))) {
+ /* out of memory error */
+ free(buffer);
+ return -1;
+ }
+ buffer = nb;
+ }
+}
+
+ssize_t readfile(const char *filename, char **pp)
+{
+ FILE *f = fopen(filename, "r");
+ ssize_t rv;
+
+ if (!f)
+ return -1;
+
+ rv = freadfile(f, pp);
+
+ fclose(f);
+
+ return rv;
+}
diff --git a/usr/kinit/resume/Kbuild b/usr/kinit/resume/Kbuild
new file mode 100644
index 0000000..c804a85
--- /dev/null
+++ b/usr/kinit/resume/Kbuild
@@ -0,0 +1,34 @@
+#
+# Kbuild file for resume
+#
+
+static-y := static/resume
+shared-y := shared/resume
+
+# common .o files
+objs := resume.o resumelib.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create lib.a with all object files (used by kinit)
+lib-y := $(objs)
+
+# Additional include paths files
+KLIBCCFLAGS += -I$(srctree)/$(src)/..
+
+# .o files used to built executables
+static/resume-y := $(objs)
+static/resume-lib := ../lib.a
+shared/resume-y := $(objs)
+shared/resume-lib := ../lib.a
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
diff --git a/usr/kinit/resume/resume.c b/usr/kinit/resume/resume.c
new file mode 100644
index 0000000..2138078
--- /dev/null
+++ b/usr/kinit/resume/resume.c
@@ -0,0 +1,25 @@
+/*
+ * Handle resume from suspend-to-disk
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "resume.h"
+
+char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s /dev/<resumedevice> [offset]\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ progname = argv[0];
+ if (argc < 2 || argc > 3)
+ usage();
+
+ return resume(argv[1], (argc > 2) ? strtoull(argv[2], NULL, 0) : 0ULL);
+}
diff --git a/usr/kinit/resume/resume.h b/usr/kinit/resume/resume.h
new file mode 100644
index 0000000..5fb929f
--- /dev/null
+++ b/usr/kinit/resume/resume.h
@@ -0,0 +1,7 @@
+#ifndef RESUME_H
+#define RESUME_H
+
+int do_resume(int argc, char *argv[]);
+int resume(const char *resume_file, unsigned long long resume_offset);
+
+#endif /* RESUME_H */
diff --git a/usr/kinit/resume/resumelib.c b/usr/kinit/resume/resumelib.c
new file mode 100644
index 0000000..03e596a
--- /dev/null
+++ b/usr/kinit/resume/resumelib.c
@@ -0,0 +1,106 @@
+/*
+ * Handle resume from suspend-to-disk
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "kinit.h"
+#include "do_mounts.h"
+#include "resume.h"
+
+#ifndef CONFIG_PM_STD_PARTITION
+# define CONFIG_PM_STD_PARTITION ""
+#endif
+
+int do_resume(int argc, char *argv[])
+{
+ const char *resume_file = CONFIG_PM_STD_PARTITION;
+ const char *resume_arg;
+ unsigned long long resume_offset;
+
+ resume_arg = get_arg(argc, argv, "resume=");
+ resume_file = resume_arg ? resume_arg : resume_file;
+ /* No resume device specified */
+ if (!resume_file[0])
+ return 0;
+
+ resume_arg = get_arg(argc, argv, "resume_offset=");
+ resume_offset = resume_arg ? strtoull(resume_arg, NULL, 0) : 0ULL;
+
+ /* Fix: we either should consider reverting the device back to
+ ordinary swap, or (better) put that code into swapon */
+ /* Noresume requested */
+ if (get_flag(argc, argv, "noresume"))
+ return 0;
+ return resume(resume_file, resume_offset);
+}
+
+int resume(const char *resume_file, unsigned long long resume_offset)
+{
+ dev_t resume_device;
+ int attr_fd = -1;
+ char attr_value[64];
+ int len;
+
+ resume_device = name_to_dev_t(resume_file);
+
+ if (major(resume_device) == 0) {
+ fprintf(stderr, "Invalid resume device: %s\n", resume_file);
+ goto failure;
+ }
+
+ if ((attr_fd = open("/sys/power/resume_offset", O_WRONLY)) < 0)
+ goto fail_offset;
+
+ len = snprintf(attr_value, sizeof attr_value,
+ "%llu",
+ resume_offset);
+
+ /* This should never happen */
+ if (len >= sizeof attr_value)
+ goto fail_offset;
+
+ if (write(attr_fd, attr_value, len) != len)
+ goto fail_offset;
+
+ close(attr_fd);
+
+ if ((attr_fd = open("/sys/power/resume", O_WRONLY)) < 0)
+ goto fail_r;
+
+ len = snprintf(attr_value, sizeof attr_value,
+ "%u:%u",
+ major(resume_device), minor(resume_device));
+
+ /* This should never happen */
+ if (len >= sizeof attr_value)
+ goto fail_r;
+
+ dprintf("kinit: trying to resume from %s\n", resume_file);
+
+ if (write(attr_fd, attr_value, len) != len)
+ goto fail_r;
+
+ /* Okay, what are we still doing alive... */
+failure:
+ if (attr_fd >= 0)
+ close(attr_fd);
+ dprintf("kinit: No resume image, doing normal boot...\n");
+ return -1;
+
+fail_offset:
+ fprintf(stderr, "Cannot write /sys/power/resume_offset "
+ "(no software suspend kernel support, or old kernel version?)\n");
+ goto failure;
+
+fail_r:
+ fprintf(stderr, "Cannot write /sys/power/resume "
+ "(no software suspend kernel support?)\n");
+ goto failure;
+}
diff --git a/usr/kinit/run-init/Kbuild b/usr/kinit/run-init/Kbuild
new file mode 100644
index 0000000..eeff906
--- /dev/null
+++ b/usr/kinit/run-init/Kbuild
@@ -0,0 +1,38 @@
+#
+# Kbuild file for run-init
+#
+
+static-y := static/run-init
+shared-y := shared/run-init
+
+# common .o files
+objs := run-init.o runinitlib.o
+
+# TODO - do we want a stripped version
+# TODO - do we want the static.g + shared.g directories?
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# force run-init to not have an executable stack (to keep READ_IMPLIES_EXEC
+# personality(2) flag from getting set and passed to init).
+EXTRA_KLIBCLDFLAGS += -z noexecstack
+
+# Additional include paths files
+KLIBCCFLAGS += -I$(srctree)/$(src)/..
+
+# .o files used to built executables
+static/run-init-y := $(objs)
+static/run-init-lib := ../lib.a
+shared/run-init-y := $(objs)
+shared/run-init-lib := ../lib.a
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c
new file mode 100644
index 0000000..6a4ad3e
--- /dev/null
+++ b/usr/kinit/run-init/run-init.c
@@ -0,0 +1,114 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Usage: exec run-init [-d caps] [-c /dev/console] [-n] [-p] /real-root /sbin/init "$@"
+ *
+ * This program should be called as the last thing in a shell script
+ * acting as /init in an initramfs; it does the following:
+ *
+ * 1. Delete all files in the initramfs;
+ * 2. Remounts /real-root onto the root filesystem;
+ * 3. Drops comma-separated list of capabilities;
+ * 4. Chroots;
+ * 5. Opens /dev/console;
+ * 6. Spawns the specified init program (with arguments.)
+ *
+ * With the -p option, it skips step 1 in order to allow the initramfs to
+ * be persisted into the running system.
+ *
+ * With the -n option, it skips steps 1, 2 and 6 and can be used to check
+ * whether the given root and init are likely to work.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "run-init.h"
+
+static const char *program;
+
+static void __attribute__ ((noreturn)) usage(void)
+{
+ fprintf(stderr,
+ "Usage: exec %s [-d caps] [-c consoledev] [-n] [-p] /real-root /sbin/init [args]\n",
+ program);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ /* Command-line options and defaults */
+ const char *console = "/dev/console";
+ const char *realroot;
+ const char *init;
+ const char *error;
+ const char *drop_caps = NULL;
+ bool dry_run = false;
+ bool persist_initramfs = false;
+ char **initargs;
+
+ /* Variables... */
+ int o;
+
+ /* Parse the command line */
+ program = argv[0];
+
+ while ((o = getopt(argc, argv, "c:d:pn")) != -1) {
+ if (o == 'c') {
+ console = optarg;
+ } else if (o == 'd') {
+ drop_caps = optarg;
+ } else if (o == 'n') {
+ dry_run = true;
+ } else if (o == 'p') {
+ persist_initramfs = true;
+ } else {
+ usage();
+ }
+ }
+
+ if (argc - optind < 2)
+ usage();
+
+ realroot = argv[optind];
+ init = argv[optind + 1];
+ initargs = argv + optind + 1;
+
+ error = run_init(realroot, console, drop_caps, dry_run, persist_initramfs, init, initargs);
+
+ if (error) {
+ fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno));
+ return 1;
+ } else {
+ /* Must have been a dry run */
+ return 0;
+ }
+}
diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h
new file mode 100644
index 0000000..5240ce7
--- /dev/null
+++ b/usr/kinit/run-init/run-init.h
@@ -0,0 +1,38 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef RUN_INIT_H
+#define RUN_INIT_H
+
+#include <stdbool.h>
+
+const char *run_init(const char *realroot, const char *console,
+ const char *drop_caps, bool dry_run,
+ bool persist_initramfs, const char *init,
+ char **initargs);
+
+#endif
diff --git a/usr/kinit/run-init/runinitlib.c b/usr/kinit/run-init/runinitlib.c
new file mode 100644
index 0000000..1c2e56a
--- /dev/null
+++ b/usr/kinit/run-init/runinitlib.c
@@ -0,0 +1,232 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * run_init(realroot, consoledev, drop_caps, persist_initramfs, init, initargs)
+ *
+ * This function should be called as the last thing in kinit,
+ * from initramfs, it does the following:
+ *
+ * - Delete all files in the initramfs;
+ * - Remounts /real-root onto the root filesystem;
+ * - Chroots;
+ * - Drops comma-separated list of capabilities;
+ * - Opens /dev/console;
+ * - Spawns the specified init program (with arguments.)
+ *
+ * On failure, returns a human-readable error message.
+ */
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include "run-init.h"
+#include "capabilities.h"
+
+/* Make it possible to compile on glibc by including constants that the
+ always-behind shipped glibc headers may not include. Classic example
+ on why the lack of ABI headers screw us up. */
+#ifndef TMPFS_MAGIC
+# define TMPFS_MAGIC 0x01021994
+#endif
+#ifndef RAMFS_MAGIC
+# define RAMFS_MAGIC 0x858458f6
+#endif
+#ifndef MS_MOVE
+# define MS_MOVE 8192
+#endif
+
+static int nuke(const char *what);
+
+static int nuke_dirent(int len, const char *dir, const char *name, dev_t me)
+{
+ int bytes = len + strlen(name) + 2;
+ char path[bytes];
+ int xlen;
+ struct stat st;
+
+ xlen = snprintf(path, bytes, "%s/%s", dir, name);
+ assert(xlen < bytes);
+
+ if (lstat(path, &st))
+ return ENOENT; /* Return 0 since already gone? */
+
+ if (st.st_dev != me)
+ return 0; /* DO NOT recurse down mount points!!!!! */
+
+ return nuke(path);
+}
+
+/* Wipe the contents of a directory, but not the directory itself */
+static int nuke_dir(const char *what)
+{
+ int len = strlen(what);
+ DIR *dir;
+ struct dirent *d;
+ int err = 0;
+ struct stat st;
+
+ if (lstat(what, &st))
+ return errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return ENOTDIR;
+
+ if (!(dir = opendir(what))) {
+ /* EACCES means we can't read it. Might be empty and removable;
+ if not, the rmdir() in nuke() will trigger an error. */
+ return (errno == EACCES) ? 0 : errno;
+ }
+
+ while ((d = readdir(dir))) {
+ /* Skip . and .. */
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+
+ err = nuke_dirent(len, what, d->d_name, st.st_dev);
+ if (err) {
+ closedir(dir);
+ return err;
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static int nuke(const char *what)
+{
+ int rv;
+ int err = 0;
+
+ rv = unlink(what);
+ if (rv < 0) {
+ if (errno == EISDIR) {
+ /* It's a directory. */
+ err = nuke_dir(what);
+ if (!err)
+ err = rmdir(what) ? errno : err;
+ } else {
+ err = errno;
+ }
+ }
+
+ if (err) {
+ errno = err;
+ return err;
+ } else {
+ return 0;
+ }
+}
+
+const char *run_init(const char *realroot, const char *console,
+ const char *drop_caps, bool dry_run,
+ bool persist_initramfs, const char *init, char **initargs)
+{
+ struct stat rst, cst, ist;
+ struct statfs sfs;
+ int confd;
+
+ /* First, change to the new root directory */
+ if (chdir(realroot))
+ return "chdir to new root";
+
+ /* This is a potentially highly destructive program. Take some
+ extra precautions. */
+
+ /* Make sure the current directory is not on the same filesystem
+ as the root directory */
+ if (stat("/", &rst) || stat(".", &cst))
+ return "stat";
+
+ if (rst.st_dev == cst.st_dev)
+ return "current directory on the same filesystem as the root";
+
+ /* Make sure we're on a ramfs */
+ if (statfs("/", &sfs))
+ return "statfs /";
+ if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
+ return "rootfs not a ramfs or tmpfs";
+
+ /* Okay, I think we should be safe... */
+
+ if (!dry_run) {
+ if (!persist_initramfs) {
+ /* Delete rootfs contents */
+ if (nuke_dir("/"))
+ return "nuking initramfs contents";
+ }
+
+ /* Overmount the root */
+ if (mount(".", "/", NULL, MS_MOVE, NULL))
+ return "overmounting root";
+ }
+
+ /* chroot, chdir */
+ if (chroot(".") || chdir("/"))
+ return "chroot";
+
+ /* Drop capabilities */
+ if (drop_capabilities(drop_caps) < 0)
+ return "dropping capabilities";
+
+ /* Open /dev/console */
+ if ((confd = open(console, O_RDWR)) < 0)
+ return "opening console";
+ if (!dry_run) {
+ dup2(confd, 0);
+ dup2(confd, 1);
+ dup2(confd, 2);
+ }
+ close(confd);
+
+ if (!dry_run) {
+ /* Spawn init */
+ execv(init, initargs);
+ return init; /* Failed to spawn init */
+ } else {
+ if (stat(init, &ist))
+ return init;
+ if (!S_ISREG(ist.st_mode) || !(ist.st_mode & S_IXUGO)) {
+ errno = EACCES;
+ return init;
+ }
+ return NULL; /* Success */
+ }
+}
diff --git a/usr/kinit/xpio.c b/usr/kinit/xpio.c
new file mode 100644
index 0000000..42a9844
--- /dev/null
+++ b/usr/kinit/xpio.c
@@ -0,0 +1,51 @@
+/*
+ * Looping versions of pread() and pwrite()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xpio.h"
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
+{
+ ssize_t ctr = 0;
+ ssize_t rv = 0;
+ char *bp = buf;
+
+ while (count) {
+ rv = pread(fd, bp, count, offset);
+
+ if (rv == 0 || (rv == -1 && errno != EINTR))
+ break;
+
+ bp += rv;
+ count -= rv;
+ offset += rv;
+ ctr += rv;
+ }
+
+ return ctr ? ctr : rv;
+}
+
+ssize_t xpwrite(int fd, void *buf, size_t count, off_t offset)
+{
+ ssize_t ctr = 0;
+ ssize_t rv = 0;
+ char *bp = buf;
+
+ while (count) {
+ rv = pwrite(fd, bp, count, offset);
+
+ if (rv == 0 || (rv == -1 && errno != EINTR))
+ break;
+
+ bp += rv;
+ count -= rv;
+ offset += rv;
+ ctr += rv;
+ }
+
+ return ctr ? ctr : rv;
+}
diff --git a/usr/kinit/xpio.h b/usr/kinit/xpio.h
new file mode 100644
index 0000000..0596a32
--- /dev/null
+++ b/usr/kinit/xpio.h
@@ -0,0 +1,11 @@
+/*
+ * kinit/xpio.h
+ */
+
+#ifndef KINIT_XPIO_H
+#define KINIT_XPIO_H
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
+ssize_t xpwrite(int fd, void *buf, size_t count, off_t offset);
+
+#endif /* KINIT_XPIO_H */
diff --git a/usr/klibc/.gitignore b/usr/klibc/.gitignore
new file mode 100644
index 0000000..5f4a9af
--- /dev/null
+++ b/usr/klibc/.gitignore
@@ -0,0 +1,12 @@
+errlist.c
+.shared-stub.o.d
+klibc*.so
+klib.list
+.klib.list.cmd
+libc.a
+libc.so
+libc.so.hash
+sha1hash
+tests/*
+!tests/Kbuild
+!tests/*.c
diff --git a/usr/klibc/CAVEATS b/usr/klibc/CAVEATS
new file mode 100644
index 0000000..39949c2
--- /dev/null
+++ b/usr/klibc/CAVEATS
@@ -0,0 +1,49 @@
+ -------------------------------------------------
+ Please note the following caveats when using klibc:
+ -------------------------------------------------
+
+optimization:
+-------------
+Compiling with -O0 is not supported. It may or may not work; please
+use -O1 if you want to do maximize debuggability.
+
+Compiling with -O0 is more likely to work on gcc 3.
+
+
+setjmp()/longjmp():
+-------------------
+setjmp() and longjmp() *do not* save signal state. sigsetjmp() and
+siglongjmp() *do* save the signal mask if the extra argument is nonzero.
+
+The standards actually state that if you pass longjmp() a final value
+of zero the library should change that to a 1! Presumably the reason
+is so people who write broken code can get away with writing
+longjmp(buf); or something equally bad. If you pass longjmp() a final
+value of 0 you get what you deserve -- setjmp() will happily return 0.
+
+
+stdio:
+------
+Only a small subset of the stdio functions are implemented. Those
+that are implemented do not buffer, although they *do* trap EINTR or
+short read/writes and iterate.
+
+_fread() and _fwrite(), which take only one size argument (like
+read/write), but do handle EINTR/short return are also available.
+
+
+namespaces:
+-----------
+klibc frequently includes headers in other headers in a way that
+exposes more symbols than POSIX says they should. "Live with it."
+
+
+theading:
+---------
+klibc is not thread-safe. Consequently, clone() or any of the
+pthreads functions are not included.
+
+
+bsd_signal vs sysv_signal:
+--------------------------
+signal() now defaults to bsd_signal().
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
new file mode 100644
index 0000000..8b13219
--- /dev/null
+++ b/usr/klibc/Kbuild
@@ -0,0 +1,219 @@
+#
+# Kbuild file for klibc
+#
+
+# Tell that we are building klibc
+export klibc-build := y
+
+# Generate syscall stubs
+klib-y += syscalls/
+# Generate socket calls stubs
+klib-y += socketcalls/
+# zlib, if configured
+klib-$(CONFIG_KLIBC_ZLIB) += zlib/
+# arch specific .o files
+klib-y += arch/$(KLIBCARCHDIR)/
+
+klib-y += vsnprintf.o snprintf.o vsprintf.o sprintf.o \
+ asprintf.o vasprintf.o \
+ vsscanf.o sscanf.o ctypes.o \
+ strntoumax.o strntoimax.o \
+ atoi.o atol.o atoll.o \
+ strtol.o strtoll.o strtoul.o strtoull.o \
+ strtoimax.o strtoumax.o \
+ globals.o exit.o atexit.o onexit.o \
+ execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
+ fork.o vfork.o wait.o wait3.o waitpid.o system.o \
+ setpgrp.o getpgrp.o daemon.o \
+ printf.o vprintf.o fprintf.o vfprintf.o perror.o \
+ statfs.o fstatfs.o umount.o \
+ creat.o open.o openat.o \
+ fread2.o fwrite2.o fgets.o fputc.o fputs.o puts.o putchar.o \
+ clock_nanosleep.o nanosleep.o sleep.o usleep.o \
+ strtotimespec.o strtotimeval.o \
+ raise.o abort.o assert.o alarm.o pause.o \
+ __signal.o sysv_signal.o bsd_signal.o siglist.o sigabbrev.o \
+ siglongjmp.o \
+ sigaction.o sigpending.o sigprocmask.o sigsuspend.o \
+ pselect.o ppoll.o \
+ pread.o pwrite.o \
+ brk.o sbrk.o malloc.o realloc.o zalloc.o calloc.o \
+ mmap.o shm_open.o shm_unlink.o \
+ memcpy.o memcmp.o memset.o memccpy.o memmem.o memswap.o \
+ memmove.o memchr.o memrchr.o bzero.o \
+ strcasecmp.o strncasecmp.o strndup.o strerror.o strsignal.o \
+ strcat.o strchr.o strcmp.o strcpy.o strdup.o strlen.o strnlen.o \
+ strncat.o strlcpy.o strlcat.o \
+ strstr.o strncmp.o strncpy.o strrchr.o \
+ strxspn.o strspn.o strcspn.o strpbrk.o strsep.o strtok.o \
+ strtok_r.o \
+ fnmatch.o \
+ gethostname.o getdomainname.o getcwd.o \
+ seteuid.o setegid.o \
+ getenv.o setenv.o putenv.o __put_env.o unsetenv.o \
+ clearenv.o nullenv.o \
+ getopt.o getopt_long.o readdir.o scandir.o alphasort.o remove.o \
+ syslog.o closelog.o pty.o isatty.o reboot.o \
+ gettimeofday.o settimeofday.o time.o \
+ lseek.o nice.o getpriority.o \
+ futimesat.o utime.o utimes.o \
+ qsort.o bsearch.o \
+ lrand48.o jrand48.o mrand48.o nrand48.o srand48.o seed48.o \
+ inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
+ inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
+ accept.o send.o recv.o \
+ access.o chmod.o chown.o dup2.o mknod.o poll.o rename.o renameat.o \
+ fstat.o fstatat.o lstat.o stat.o \
+ lchown.o link.o rmdir.o unlink.o mkdir.o \
+ readlink.o realpath.o select.o symlink.o pipe.o \
+ ctype/isalnum.o ctype/isalpha.o ctype/isascii.o \
+ ctype/isblank.o ctype/iscntrl.o ctype/isdigit.o \
+ ctype/isgraph.o ctype/islower.o ctype/isprint.o \
+ ctype/ispunct.o ctype/isspace.o ctype/isupper.o \
+ ctype/isxdigit.o ctype/tolower.o ctype/toupper.o \
+ userdb/getgrgid.o userdb/getgrnam.o userdb/getpwnam.o \
+ userdb/getpwuid.o userdb/root_group.o userdb/root_user.o \
+ setmntent.o endmntent.o getmntent.o \
+ stdio/fclose.o stdio/fopen.o stdio/fdopen.o \
+ stdio/fread.o stdio/fwrite.o stdio/fflush.o \
+ stdio/ungetc.o stdio/fgetc.o \
+ stdio/fseek.o stdio/ftell.o stdio/rewind.o \
+ stdio/fileno.o stdio/feof.o stdio/ferror.o stdio/clearerr.o \
+ sysconf/sysconf.o
+
+klib-$(CONFIG_KLIBC_ERRLIST) += errlist.o
+
+ifeq ($(CONFIG_KLIBC_ERRLIST),y)
+KLIBCCFLAGS_strerror.o += -DWITH_ERRLIST
+endif
+
+# These pass a huge maximum length to the corresponding length-limiting
+# functions
+KLIBCCFLAGS_sprintf.o += $(call cc-option,-Wno-format-truncation, )
+KLIBCCFLAGS_vsprintf.o += $(call cc-option,-Wno-format-truncation, )
+
+# Clang 14 optimises zalloc() to recursively call calloc(), without
+# this option
+KLIBCCFLAGS_zalloc.o += $(call cc-option,-fno-builtin-malloc, )
+
+# sigsuspend.c includes <klibc/havesyscall.h> generated by syscalls/
+# build, so require that to build first
+$(obj)/sigsuspend.o: $(obj)/syscalls/klib.list
+
+#####
+# Shared definitions
+LIBC := libc.a
+SOLIB := libc.so
+SOHASH := klibc.so
+CRT0 := arch/$(KLIBCARCHDIR)/crt0.o
+SHARED_STUB := shared-stub.o
+
+always := $(LIBC)
+ifdef KLIBCSHAREDFLAGS
+always += $(SOLIB) $(SOHASH) $(SHARED_STUB)
+endif
+LIBC := $(call objectify,$(LIBC))
+SOLIB := $(call objectify,$(SOLIB))
+SOHASH := $(call objectify,$(SOHASH))
+CRT0 := $(call objectify,$(CRT0))
+SHARED_STUB := $(call objectify,$(SHARED_STUB))
+
+SOLIBHASH = $(shell cat $(SOLIB).hash)
+
+#####
+# Readable errormessages extracted from src..
+targets += errlist.c
+quiet_cmd_errlist = GEN $@
+ cmd_errlist = $(PERL) $< $(call flags,KLIBCCPPFLAGS) -errlist > $@ \
+ || rm -f $@
+
+$(obj)/errlist.c: $(srctree)/$(src)/makeerrlist.pl
+ $(call cmd,errlist)
+
+
+# all .o files for all dirs
+klib-o-files = $(shell cat $(obj)/klib.list \
+ $(addsuffix /klib.list, $(klib-dirs)))
+######
+# Build static library: libc.a
+targets += libc.a __static_init.o
+quiet_cmd_libc = KLIBCAR $@
+ cmd_libc = rm -f $@; \
+ $(KLIBCAR) Dcq $@ \
+ $(call objectify,__static_init.o) $(klib-o-files); \
+ $(KLIBCRANLIB) $@
+
+$(LIBC): $(call objectify,__static_init.o) $(obj)/klib.list FORCE
+ $(call if_changed,libc)
+
+######
+# Build shared library
+targets += libc.so __shared_init.o
+
+quiet_cmd_libcso = KLIBCLD $@
+ cmd_libcso = $(KLIBCLD) $(KLIBCLDFLAGS) $(KLIBCSHAREDFLAGS) -o $@ \
+ --start-group \
+ $(CRT0) \
+ $(call objectify,__shared_init.o) \
+ $(klib-o-files) \
+ $(KLIBCLIBGCC) \
+ --end-group
+
+$(SOLIB): $(call objectify,__shared_init.o) $(obj)/klib.list FORCE
+ $(call if_changed,libcso)
+
+
+#####
+# Build sha1 hash values
+targets += klibc.so libc.so.hash
+hostprogs-y := sha1hash
+clean-files += klibc-???????????????????????????.so
+
+quiet_cmd_solibhash = HASH $@
+ cmd_solibhash = $(KLIBCNM) $< | egrep '^[0-9a-fA-F]+ [ADRTW] ' | \
+ sort | $(obj)/sha1hash > $@
+$(SOLIB).hash: $(SOLIB) $(obj)/sha1hash FORCE
+ $(call if_changed,solibhash)
+
+quiet_cmd_sohash = GEN $@
+ cmd_sohash = cat $< > $@; \
+ $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@; \
+ chmod a+x $@; \
+ rm -f $(obj)/klibc-???????????????????????????.so; \
+ ln -f $@ $(obj)/klibc-$(SOLIBHASH).so
+$(SOHASH): $(SOLIB) $(SOLIB).hash
+ $(call cmd,sohash)
+
+
+#####
+# build shared-stub.o
+targets += shared-stub.o
+
+quiet_cmd_interp = BUILD $@
+ cmd_interp = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__ \
+ -DLIBDIR=\"$(SHLIBDIR)\" \
+ -DSOHASH=\"$(SOLIBHASH)\" \
+ -c -o $@ $<
+
+$(SHARED_STUB): $(obj)/shared-stub.S $(SOLIB).hash
+ $(call if_changed,interp)
+
+#####
+# Install klibc
+install-rule:
+ @echo " INSTALL klibc to $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib"
+ $(Q)$(foreach f, $(LIBC) $(CRT0), \
+ $(shell $(install-data) $(f) \
+ $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib))
+ifdef KLIBCSHAREDFLAGS
+ $(Q)$(foreach f, $(SOLIB) $(SHARED_STUB), \
+ $(shell $(install-data) $(f) \
+ $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib))
+ $(Q)$(install-lib) $(obj)/klibc-$(SOLIBHASH).so \
+ $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib
+ $(Q)$(install-lib) $(obj)/klibc-$(SOLIBHASH).so \
+ $(INSTALLROOT)$(SHLIBDIR)
+endif
+
+# Directories to visit during clean and install
+subdir- := arch/$(KLIBCARCHDIR)/
diff --git a/usr/klibc/LICENSE b/usr/klibc/LICENSE
new file mode 100644
index 0000000..aa6d7a7
--- /dev/null
+++ b/usr/klibc/LICENSE
@@ -0,0 +1,73 @@
+This license applies to all files in directory and its subdirectories,
+unless otherwise noted in individual files.
+
+
+Some files are derived from files derived from the include/ directory
+of the Linux kernel, and are licensed under the terms of the GNU
+General Public License, version 2, as released by the Free Software
+Foundation, Inc.; incorporated herein by reference.
+
+ -----
+
+Some files are derived from files copyrighted by the Regents of The
+University of California, and are available under the following
+license:
+
+Note: The advertising clause in the license appearing on BSD Unix
+files was officially rescinded by the Director of the Office of
+Technology Licensing of the University of California on July 22
+1999. He states that clause 3 is "hereby deleted in its entirety."
+
+ * Copyright (c)
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+
+ -----
+
+For all remaining files, the following license applies:
+
+ * 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, 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:
+ *
+ * Any copyright notice(s) 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 AUTHORS OR 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.
diff --git a/usr/klibc/README.klibc b/usr/klibc/README.klibc
new file mode 100644
index 0000000..1a9e09f
--- /dev/null
+++ b/usr/klibc/README.klibc
@@ -0,0 +1,147 @@
+Introduction
+============
+
+This is klibc, what is intended to be a minimalistic libc subset for
+use with initramfs. It is deliberately written for small size,
+minimal entanglement, and portability, not speed. It is definitely a
+work in progress, and a lot of things are still missing.
+
+Building
+========
+
+The build procedure is not very polished yet, but for a native build
+with the default configuration it should be simple:
+
+1. In a recent Linux kernel source directory, run:
+ make headers_install INSTALL_HDR_PATH=<klibc-source-dir>/linux
+2. In the klibc source directory, run:
+ make
+
+Cross-compiling
+---------------
+
+If you're cross-compiling, you need to set KLIBCARCH to the
+appropriate architecture, and set CROSS_COMPILE to your toolchain
+prefix, on the "make" command line. You also need to set ARCH to the
+appropriate kernel architecture name on the "make headers_install"
+command line.
+
+IMPORTANT: if you're on a 64-bit machine with a 32-bit userland, and
+you want to build the 32-bit version: you need to set KLIBCARCH to the
+32-bit architecture. Building the 32-bit architecture usually (but
+not always) produces smaller binaries.
+
+If you are on ARM, and want to build a thumb version of the library
+(this is supported), change OPTFLAGS in arch/arm/MCONFIG to build
+thumb code.
+
+Out-of-tree builds
+------------------
+
+It is possible to use a separate build directory so that build
+products are not created in source directories. To do this,
+create the build directory and in that directory run:
+ make -f <source-dir>/Makefile KBUILD_SRC=<source-dir>
+
+Build configuration
+-------------------
+
+The build configuration is defined in a ".config" file in the
+build directory. If this file does not already exist, it is
+created as a copy of the "defconfig" source file.
+
+The configuration variables are:
+
+* CONFIG_KLIBC_ERRLIST (bool): Include standard error strings for
+ strerror(). If disabled, strerror() returns the error number as a
+ string.
+* CONFIG_KLIBC_ZLIB (bool): Include zlib decompression functions. If
+ disabled, kinit can only load uncompressed ramdisk images.
+* CONFIG_KLIBC_ZIP (bool): Include compression support in the gzip
+ command.
+* CONFIG_DEBUG_INFO (bool): Install all executables and the shared
+ library with debug information and build IDs included. If
+ disabled, the executables and shared library are stripped when
+ installed.
+
+For arm only:
+
+* CONFIG_KLIBC_THUMB (bool): Compile all code to Thumb instructions,
+ which should reduce code size slightly. If disabled, regular ARM
+ instructions are used.
+* CONFIG_AEABI (bool): Compile ARM code to use the ARM EABI and the
+ "new" system call ABI.
+
+If both CONFIG_KLIBC_THUMB and CONFIG_AEABI are disabled, the GNU APCS
+and the old system call ABI are used.
+
+For i386 only:
+
+* CONFIG_REGPARM (bool): Optimise function calls by passing the first
+ 3 function parameters in registers.
+
+For mips64 only:
+
+* CONFIG_KLIBC_MIPS_USE_CB (bool): Use compact branch instructions.
+ This should be enabled when targetting MIPS R6 and must be disabled
+ for older MIPS ISAs.
+
+Building without kernel source
+------------------------------
+
+If you already have a copy of the current kernel UAPI headers, you
+don't need the kernel source as well. You can either:
+
+1. Copy or link to the UAPI headers so that they appear under the
+ "linux/include" subdirectory.
+2. Set the KLIBCKERNELSRC variable on the "make" command line to
+ point to the *parent* of the UAPI headers directory.
+
+Architecture support
+====================
+
+The following is the last known status of various architectures:
+
+ alpha: Working
+ arm-thumb: Working
+ arm: Working
+ arm64: Working
+ h8300: Not yet ported
+ i386: Working
+ ia64: Working
+ m68k: Working
+ mips: Working
+ mips64: Working
+ parisc: Working
+ parisc64: Not yet ported
+ ppc: Working
+ ppc64: Working
+ riscv64: Working
+ s390: Working
+ s390x: Working
+ sh: Working
+ sparc: Working
+ sparc64: Working
+ x86-64: Working
+ xtensa: Not yet ported
+
+Shared library support requires recent binutils on many architectures.
+
+Note that even the "working" ones likely have bugs. Please report
+them if you run into them.
+
+Testing
+=======
+
+Try the test programs in the tests/ directory. They should run...
+
+Contact
+=======
+
+Contact the klibc mailing list:
+
+ https://www.zytor.com/mailman/listinfo/klibc
+
+... for more info.
+
+ -hpa
diff --git a/usr/klibc/SOCKETCALLS.def b/usr/klibc/SOCKETCALLS.def
new file mode 100644
index 0000000..97413de
--- /dev/null
+++ b/usr/klibc/SOCKETCALLS.def
@@ -0,0 +1,22 @@
+/* -*- c -*-
+ *
+ * These are calls that are invoked via the socketcall mechanism
+ * Note that on most architectures this is simply #included into
+ * SYSCALLS.def.
+ */
+<?> int socket(int, int, int);
+<?> int bind(int, const struct sockaddr *, int);
+<?> int connect(int, const struct sockaddr *, socklen_t);
+<?> int listen(int, int);
+<?> int accept(int, struct sockaddr *, socklen_t *);
+<?> int accept4(int, struct sockaddr *, socklen_t *, int);
+<?> int getsockname(int, struct sockaddr *, socklen_t *);
+<?> int getpeername(int, struct sockaddr *, socklen_t *);
+<?> int socketpair(int, int, int, int *);
+<?> int sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
+<?> int recvfrom(int, void *, size_t, unsigned int, struct sockaddr *, socklen_t *);
+<?> int shutdown(int, int);
+<?> int setsockopt(int, int, int, const void *, socklen_t);
+<?> int getsockopt(int, int, int, void *, socklen_t *);
+<?> int sendmsg(int, const struct msghdr *, unsigned int);
+<?> int recvmsg(int, struct msghdr *, unsigned int);
diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def
new file mode 100644
index 0000000..9b6b112
--- /dev/null
+++ b/usr/klibc/SYSCALLS.def
@@ -0,0 +1,264 @@
+/* -*- c -*-
+ *
+ * This is a list of system calls we invoke "directly". These
+ * are generated into syscall stubs in their own files, so the
+ * linker can do its job properly.
+ *
+ * The full description of a line is:
+ * [<[?][!]arch,...>] type [sysname,...][@systype][::funcname](args);
+ *
+ * ? means only instantiate this system call if present in asm/unistd.h
+ */
+
+#include <asm/unistd.h>
+#include <klibc/sysconfig.h>
+#include <bitsize.h>
+
+/*
+ * Process-related syscalls
+ */
+void _exit,exit::_exit(int);
+<?!ia64> pid_t clone::__clone(unsigned long, void *);
+<?ia64> pid_t clone::__clone2(unsigned long, void *, void *);
+# if ! _KLIBC_NO_MMU
+<!sparc,sparc64,ia64,arm64,riscv64,loongarch64> pid_t fork();
+<sparc,sparc64> pid_t fork@forkish();
+#endif
+#if _KLIBC_REAL_VFORK
+/*
+ * A lot of architectures need architecture-specific vfork
+ * stubs, due to the no-stack requirement. These are the
+ * architectures which do not.
+ */
+<alpha,ppc,ppc64,sh,s390,s390x> pid_t vfork();
+<sparc,sparc64> pid_t vfork@forkish();
+#endif
+<!alpha> pid_t getpid();
+<alpha> pid_t getxpid@dual0::getpid();
+int setpgid(pid_t, pid_t);
+pid_t getpgid(pid_t);
+<!alpha> pid_t getppid();
+<alpha> pid_t getxpid@dual1::getppid();
+pid_t setsid();
+pid_t getsid(pid_t);
+pid_t wait4(pid_t, int *, int, struct rusage *);
+int execve(const char *, char * const *, char * const *);
+<?> int nice(int);
+<alpha,ia64> int getpriority(int, int);
+<!alpha,ia64> int getpriority::__getpriority(int, int);
+int setpriority(int, int, int);
+int getrusage(int, struct rusage *);
+int sched_setscheduler(pid_t, int, const struct sched_param *);
+<?> int sched_setaffinity(pid_t, unsigned int, unsigned long *);
+<?> int sched_getaffinity(pid_t, unsigned int, unsigned long *);
+int sched_yield();
+<i386> int prctl@varadic(int, unsigned long, unsigned long, unsigned long, unsigned long);
+<!i386> int prctl(int, unsigned long, unsigned long, unsigned long, unsigned long);
+
+/*
+ * User and group IDs
+ */
+int setuid32,setuid::setuid(uid_t);
+int setgid32,setgid::setgid(gid_t);
+<!alpha> uid_t getuid32,getuid::getuid();
+<alpha> uid_t getxuid@dual0::getuid();
+<!alpha> gid_t getgid32,getgid::getgid();
+<alpha> gid_t getxgid@dual0::getgid();
+<!alpha> uid_t geteuid32,geteuid::geteuid();
+<alpha> uid_t getxuid@dual1::geteuid();
+<!alpha> gid_t getegid32,getegid::getegid();
+<alpha> gid_t getxgid@dual1::getegid();
+int getgroups32,getgroups::getgroups(int, gid_t *);
+int setgroups32,setgroups::setgroups(size_t, const gid_t *);
+int setreuid32,setreuid::setreuid(uid_t, uid_t);
+int setregid32,setregid::setregid(gid_t, gid_t);
+int setfsuid32,setfsuid::setfsuid(uid_t);
+int setfsgid32,setfsgid::setfsgid(gid_t);
+int setresuid32,setresuid::setresuid(int, uid_t, uid_t, uid_t);
+
+/*
+ * POSIX Capabilities
+ */
+int capget(cap_user_header_t, cap_user_data_t);
+int capset(cap_user_header_t, cap_user_data_t);
+
+/*
+ * Filesystem-related system calls
+ */
+int mount(const char *, const char *, const char *, unsigned long, const void *);
+<!alpha,ia64> int umount2(const char *, int);
+<alpha,ia64> int umount::umount2(const char *, int);
+<?> int pivot_root(const char *, const char *);
+int sync();
+#ifdef __NR_statfs64
+int statfs64::__statfs64(const char *, size_t, struct statfs *);
+#else
+int statfs(const char *, struct statfs *);
+#endif
+#ifdef __NR_fstatfs64
+int fstatfs64::__fstatfs64(int, size_t, struct statfs *);
+#else
+int fstatfs(int, struct statfs *);
+#endif
+int swapon(const char *, int);
+int swapoff(const char *);
+
+/*
+ * Inode-related system calls
+ */
+<?> int access(const char *, int);
+int faccessat(int, const char *, int, int);
+<?> int link(const char *, const char *);
+<?> int linkat(int, const char *, int, const char *, int);
+<?> int unlink(const char *);
+<?> int unlinkat(int, const char *, int);
+int chdir(const char *);
+int fchdir(int);
+<?> int rename(const char *, const char *);
+<?> int renameat(int, const char *, int, const char *);
+<?> int renameat2(int, const char *, int, const char *, unsigned int);
+<?> int mknod(const char *, mode_t, dev_t);
+<?> int mknodat(int, const char *, mode_t, dev_t);
+<?> int chmod(const char *, mode_t);
+int fchmod(int, mode_t);
+<?> int fchmodat(int, const char *, mode_t, int);
+<?> int mkdir(const char *, mode_t);
+<?> int mkdirat(int, const char *, mode_t);
+<?> int rmdir(const char *);
+<?!alpha,ia64,mips,mips64,sh,sparc,sparc64> int pipe(int *);
+int pipe2(int *, int);
+mode_t umask(mode_t);
+int chroot(const char *);
+<?> int symlink(const char *, const char *);
+<?> int symlinkat(const char *, int, const char *);
+<?> int readlink(const char *, char *, size_t);
+<?> int readlinkat(int, const char *, char *, int);
+int statx(int, const char *, int, unsigned int, struct statx *);
+int getdents64,getdents::getdents(unsigned int, struct dirent *, unsigned int);
+<?> int chown32,chown::chown(const char *, uid_t, gid_t);
+int fchown32,fchown::fchown(int, uid_t, gid_t);
+<?> int fchownat(int, const char *, uid_t, gid_t, int);
+<?> int lchown32,lchown::lchown(const char *, uid_t, gid_t);
+int getcwd::__getcwd(char *, size_t);
+<32> int utimensat_time64::utimensat(int, const char *, const struct timespec *, int);
+<64> int utimensat(int, const char *, const struct timespec *, int);
+<?> int inotify_init();
+<?> int inotify_add_watch(int, const char *, __u32);
+<?> int inotify_rm_watch(int, __u32);
+
+/*
+ * I/O operations
+ */
+<!i386,m68k,64> int open::__open(const char *, int, mode_t);
+<?!i386,m68k,64> int openat::__openat(int, const char *, int, mode_t);
+<?64> int open(const char *, int, mode_t);
+<64> int openat(int, const char *, int, mode_t);
+ssize_t read(int, void *, size_t);
+ssize_t write(int, const void *, size_t);
+int close(int);
+<64> off_t lseek(int, off_t, int);
+<32> int _llseek::__llseek(int, unsigned long, unsigned long, off_t *, int);
+int dup(int);
+<?> int dup2(int, int);
+int dup3(int, int, int);
+<i386> int fcntl64@varadic::fcntl(int, int, unsigned long);
+<ppc64> int fcntl(int, int, unsigned long);
+<!i386,ppc64> int fcntl64,fcntl::fcntl(int, int, unsigned long);
+int ioctl(int, int, void *);
+int flock(int, int);
+<32> int pselect6_time64::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *);
+<64> int pselect6::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *);
+<?> int poll(struct pollfd *, nfds_t, long);
+<32> int ppoll_time64::__ppoll(struct pollfd *, nfds_t, struct timespec *, const sigset_t *, size_t);
+<64> int ppoll::__ppoll(struct pollfd *, nfds_t, struct timespec *, const sigset_t *, size_t);
+int fsync(int);
+int fdatasync,fsync::fdatasync(int);
+int readv(int, const struct iovec *, int);
+int writev(int, const struct iovec *, int);
+int ftruncate64,ftruncate::ftruncate(int, off_t);
+<parisc> ssize_t pread64,pread::__pread(int, void *, size_t, off_t);
+<parisc> ssize_t pwrite64,pwrite::__pwrite(int, void *, size_t, off_t);
+<!parisc> ssize_t pread64,pread::pread(int, void *, size_t, off_t);
+<!parisc> ssize_t pwrite64,pwrite::pwrite(int, void *, size_t, off_t);
+int sync_file_range,fdatasync,fsync::sync_file_range(int, off_t, off_t, unsigned int);
+<?> int splice(int, off_t *, int, off_t *, size_t, unsigned int);
+<?> int tee(int, int, size_t, unsigned int);
+ssize_t sendfile64,sendfile::sendfile(int, int, off_t *, size_t, off_t);
+
+/*
+ * Signal operations
+ */
+<!sparc,sparc64,alpha,ia64> int rt_sigaction::__rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
+<sparc,sparc64> int rt_sigaction::____rt_sigaction(int, const struct sigaction *, struct sigaction *, void *, size_t);
+<alpha> int rt_sigaction::____rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t, void *);
+<ia64> int rt_sigaction::____rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
+int rt_sigsuspend::__rt_sigsuspend(const sigset_t *, size_t);
+int rt_sigpending::__rt_sigpending(sigset_t *, size_t);
+int rt_sigprocmask::__rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
+<s390,s390x,sparc,sparc64> void rt_sigreturn::__sigreturn();
+int kill(pid_t, int);
+<?> unsigned int alarm(unsigned int);
+int getitimer(int, struct itimerval *);
+int setitimer(int, const struct itimerval *, struct itimerval *);
+
+/*
+ * Time-related system calls
+ */
+clock_t times(struct tms *);
+int gettimeofday::__gettimeofday(void *, struct timezone *);
+int settimeofday::__settimeofday(const void *, const struct timezone *);
+<32> int clock_gettime64::clock_gettime(clockid_t, struct timespec *);
+<64> int clock_gettime(clockid_t, struct timespec *);
+<32> int clock_settime64::clock_settime(clockid_t, const struct timespec *);
+<64> int clock_settime(clockid_t, const struct timespec *);
+<32> int clock_nanosleep_time64::__clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
+<64> int clock_nanosleep::__clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *);
+<?> int pause();
+
+/*
+ * Memory
+ */
+<?> void * brk::__brk(void *);
+int munmap(void *, size_t);
+void * mremap(void *, size_t, size_t, unsigned long);
+int msync(const void *, size_t, int);
+int mprotect(const void *, size_t, int);
+# if _KLIBC_USE_MMAP2
+<!s390> void * mmap2::__mmap2(void *, size_t, int, int, int, long);
+# else
+<!s390x> void * mmap(void *, size_t, int, int, int, long);
+int mlockall(int);
+int munlockall();
+int mlock(const void *, size_t);
+int munlock(const void *, size_t);
+#endif
+
+/*
+ * System stuff
+ */
+int uname(struct utsname *);
+int setdomainname(const char *, size_t);
+int sethostname(const char *, size_t);
+long init_module(void *, unsigned long, const char *);
+long finit_module(int, const char *, int);
+long delete_module(const char *, unsigned int);
+int reboot::__reboot(int, int, int, void *);
+int syslog::klogctl(int, char *, int);
+int sysinfo(struct sysinfo *);
+long kexec_load(void *, unsigned long, struct kexec_segment *, unsigned long);
+
+/*
+ * Low-level I/O (generally architecture-specific);
+ */
+<i386,x86_64> int iopl(int);
+<i386,x86_64> int ioperm(unsigned long, unsigned long, int);
+<i386> int vm86(struct vm86_struct *);
+
+/*
+ * Most architectures have the socket interfaces using regular
+ * system calls.
+ */
+<?!i386> long socketcall::__socketcall(int, const unsigned long *);
+#if ! _KLIBC_SYS_SOCKETCALL
+#include "SOCKETCALLS.def"
+#endif
diff --git a/usr/klibc/__put_env.c b/usr/klibc/__put_env.c
new file mode 100644
index 0000000..30d415c
--- /dev/null
+++ b/usr/klibc/__put_env.c
@@ -0,0 +1,74 @@
+/*
+ * __put_env.c - common code for putenv() and setenv()
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+static size_t __environ_size;
+static char **__environ_alloc;
+
+/* str should be a duplicated version of the input string;
+ len is the length of the key including the = sign */
+
+int __put_env(char *str, size_t len, int overwrite)
+{
+ static char *const null_environ = { NULL };
+ char **p, *q;
+ char **newenv;
+ size_t n;
+
+ if (!environ)
+ environ = (char **)null_environ;
+
+ n = 1; /* Include space for final NULL */
+ for (p = environ; (q = *p); p++) {
+ n++;
+ if (!strncmp(q, str, len)) {
+ if (!overwrite)
+ free(str);
+ else
+ *p = str; /* Possible memory leak... */
+ return 0;
+ }
+ }
+
+ if (__environ_alloc && environ != __environ_alloc) {
+ free(__environ_alloc);
+ __environ_alloc = NULL;
+ }
+
+ /* Need to extend the environment */
+ if (n < __environ_size) {
+ p[1] = NULL;
+ *p = str;
+ return 0;
+ } else {
+ if (__environ_alloc) {
+ newenv =
+ realloc(__environ_alloc,
+ (__environ_size << 1) * sizeof(char *));
+ if (!newenv)
+ return -1;
+
+ __environ_size <<= 1;
+ } else {
+ /* Make a reasonable guess how much more space
+ we need */
+ size_t newsize = n + 32;
+ newenv = malloc(newsize * sizeof(char *));
+ if (!newenv)
+ return -1;
+
+ memcpy(newenv, environ, n * sizeof(char *));
+ __environ_size = newsize;
+ }
+ newenv[n-1] = str; /* Old NULL position */
+ newenv[n] = NULL;
+ environ = newenv;
+ }
+ return 0;
+}
diff --git a/usr/klibc/__shared_init.c b/usr/klibc/__shared_init.c
new file mode 100644
index 0000000..592a3db
--- /dev/null
+++ b/usr/klibc/__shared_init.c
@@ -0,0 +1,2 @@
+#define SHARED 1
+#include "libc_init.c"
diff --git a/usr/klibc/__signal.c b/usr/klibc/__signal.c
new file mode 100644
index 0000000..d174b8e
--- /dev/null
+++ b/usr/klibc/__signal.c
@@ -0,0 +1,20 @@
+/*
+ * __signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t __signal(int signum, __sighandler_t handler, int flags)
+{
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sa.sa_flags = flags;
+ sigemptyset(&sa.sa_mask);
+
+ if (sigaction(signum, &sa, &sa)) {
+ return (__sighandler_t) SIG_ERR;
+ } else {
+ return (__sighandler_t) sa.sa_handler;
+ }
+}
diff --git a/usr/klibc/__static_init.c b/usr/klibc/__static_init.c
new file mode 100644
index 0000000..0b59eed
--- /dev/null
+++ b/usr/klibc/__static_init.c
@@ -0,0 +1,2 @@
+#define SHARED 0
+#include "libc_init.c"
diff --git a/usr/klibc/abort.c b/usr/klibc/abort.c
new file mode 100644
index 0000000..4629a17
--- /dev/null
+++ b/usr/klibc/abort.c
@@ -0,0 +1,18 @@
+/*
+ * abort.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+void abort(void)
+{
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGABRT);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ raise(SIGABRT);
+ _exit(255); /* raise() should have killed us */
+}
diff --git a/usr/klibc/accept.c b/usr/klibc/accept.c
new file mode 100644
index 0000000..6057544
--- /dev/null
+++ b/usr/klibc/accept.c
@@ -0,0 +1,16 @@
+/*
+ * accept.c
+ *
+ * Some architectures need to wrap the system call
+ */
+
+#include <sys/socket.h>
+
+#if !_KLIBC_SYS_SOCKETCALL && defined(__NR_accept4) && !defined(__NR_accept)
+
+int accept(int socket, struct sockaddr *address, socklen_t *addr_len)
+{
+ return accept4(socket, address, addr_len, 0);
+}
+
+#endif
diff --git a/usr/klibc/access.c b/usr/klibc/access.c
new file mode 100644
index 0000000..0f24856
--- /dev/null
+++ b/usr/klibc/access.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_access
+
+int access(const char *pathname, int mode)
+{
+ return faccessat(AT_FDCWD, pathname, mode, 0);
+}
+
+#endif /* __NR_access */
diff --git a/usr/klibc/alarm.c b/usr/klibc/alarm.c
new file mode 100644
index 0000000..8bd74c5
--- /dev/null
+++ b/usr/klibc/alarm.c
@@ -0,0 +1,25 @@
+/*
+ * alarm.c
+ */
+
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_alarm
+
+/* Emulate alarm() via setitimer() */
+
+unsigned int alarm(unsigned int seconds)
+{
+ struct itimerval iv;
+
+ iv.it_interval.tv_sec = iv.it_interval.tv_usec = 0;
+ iv.it_value.tv_sec = seconds;
+ iv.it_value.tv_usec = 0;
+
+ setitimer(ITIMER_REAL, &iv, &iv);
+
+ return iv.it_value.tv_sec + (iv.it_value.tv_usec ? 1 : 0);
+}
+
+#endif
diff --git a/usr/klibc/alphasort.c b/usr/klibc/alphasort.c
new file mode 100644
index 0000000..d420495
--- /dev/null
+++ b/usr/klibc/alphasort.c
@@ -0,0 +1,12 @@
+/*
+ * alphasort.c: alphasort
+ */
+
+#include <string.h>
+
+#include <dirent.h>
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+ return strcmp((*a)->d_name, (*b)->d_name);
+}
diff --git a/usr/klibc/arch/README.klibc.arch b/usr/klibc/arch/README.klibc.arch
new file mode 100644
index 0000000..662b9d3
--- /dev/null
+++ b/usr/klibc/arch/README.klibc.arch
@@ -0,0 +1,81 @@
+To port klibc to a new architecture, you need:
+
+a) A directory structure
+
+Each archtecture has a klibc/arch/ directory, which should include an
+MCONFIG and a Makefile.inc file, and an include/arch/ directory, which
+includes some architecture-specific header files, including
+klibc/archconfig.h.
+
+
+b) Architecture-specific configuration
+ (include/arch/*/klibc/sysconfig.h)
+
+This file can set configuration variables from
+include/klibc/sysconfig.h.
+
+
+c) Startup code
+ (klibc/arch/*/crt0.S)
+
+The crt0.S assembly routine typically corresponds to the following
+pseudo-C code. In addition, each architecture needs any support
+routines that gcc-generated code expects to find in the system library
+-- Alpha, for example, needs divide subroutines.
+
+The "getenvtest" test program is a very good test for proper crt0.S
+functionality.
+
+
+extern __noreturn __libc_init(void *, void *);
+
+__noreturn _start(void)
+{
+ void *elf_data = get_elf_data_address(); /* Usually the stack address */
+ void *atexit_ptr = get_atexit_ptr(); /* Usually in a register */
+
+ /* Some architectures need this for debugging to work */
+ setup_null_stack_frame_if_necessary();
+
+ __libc_init(elf_data, atexit_ptr);
+}
+
+
+d) A setenv implementation
+ (klibc/arch/*/setjmp.S, include/arch/*klibc/archsetjmp.h)
+
+On most (but not all!) architectures, this entails creating a setjmp
+buffer big enough to hold all callee-saved registers, plus the stack
+pointer and the return address. In setjmp.S you have:
+
+* A "setjmp" function that writes out the callee-saved registers, the
+ stack pointer and the return address to the buffer pointed to by the
+ first argument, and then returns zero normally.
+
+ On some architectures you need to take some kind of action to make
+ sure the contents of the stack is actually manifest in memory and
+ not cached in the CPU. In some cases (e.g. on SPARC) this will
+ automatically spill the registers onto the stack; then they don't
+ need to be spilled into the jmp_buf.
+
+* A "longjmp" function that read back these same registers from the
+ jmp_buf pointed to by the first argument, and returns the second
+ argument *to the address specified in the jmp_buf*.
+
+ On some architectures you need to take some kind of action to flush
+ any cached stack data or return stack.
+
+
+e) Any support functions needed by gcc, *unless* they are in libgcc
+ *and* libgcc is usable for klibc on your particular platform. If
+ libgcc isn't usable for klibc (on MIPS, for example, libgcc is
+ compiled in a way that is not compatible with klibc) there are
+ reasonably good clones of most of the libgcc functions in the libgcc
+ directory. To use them, add them to ARCHOBJS in
+ klibc/arch/*/Makefile.inc.
+
+
+f) A link location for the shared klibc. This should be specified in
+ SHAREDFLAGS in klibc/arch/*/MCONFIG.
+
+ This is not applicable to no-MMU architectures.
diff --git a/usr/klibc/arch/alpha/Kbuild b/usr/klibc/arch/alpha/Kbuild
new file mode 100644
index 0000000..715a430
--- /dev/null
+++ b/usr/klibc/arch/alpha/Kbuild
@@ -0,0 +1,53 @@
+# -*- makefile -*-
+#
+# arch/alpha/Makefile.inc
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+always := crt0.o
+targets := crt0.o
+klib-y := pipe.o sigaction.o setjmp.o sigreturn.o syscall.o sysdual.o
+
+# Special CFLAGS for the divide code
+DIVCFLAGS = $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS) \
+ -O3 -fomit-frame-pointer -fcall-saved-1 -fcall-saved-2 \
+ -fcall-saved-3 -fcall-saved-4 -fcall-saved-5 -fcall-saved-6 \
+ -fcall-saved-7 -fcall-saved-8 -ffixed-15 -fcall-saved-16 \
+ -fcall-saved-17 -fcall-saved-18 -fcall-saved-19 -fcall-saved-20 \
+ -fcall-saved-21 -fcall-saved-22 -ffixed-23 -fcall-saved-24 \
+ -ffixed-25 -ffixed-27
+
+div-objs := __divqu.o __remqu.o __divq.o __remq.o
+div-objs += __divlu.o __remlu.o __divl.o __reml.o
+klib-y += $(div-objs)
+
+quiet_cmd_regswap = REGSWAP $@
+ cmd_regswap = sed -e 's/\$$0\b/$$27/g' -e 's/\$$24\b/$$99/g' \
+ -e 's/\$$16\b/$$24/g' -e 's/\$$17\b/$$25/g' \
+ -e 's/\$$26\b/$$23/g' -e 's/\$$99\b/$$16/g' < $< > $@
+
+# Use static pattern rule to avoid using a temporary file
+$(addprefix $(obj)/,$(div-objs:.o=.S)): $(obj)/%.S: $(obj)/%.ss
+ $(call if_changed,regswap)
+
+quiet_cmd_genss = DIV-CC $@
+ cmd_genss = $(CC) $(DIVCFLAGS) $(FILE_CFLAGS) \
+ $(call flags,KLIBCCPPFLAGS) \
+ -DNAME=$(basename $(notdir $@)) -S -o $@ $<
+
+$(obj)/%.ss: $(obj)/divide.c
+ $(call if_changed,genss)
+
+$(obj)/__divqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=64
+$(obj)/__remqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=64
+$(obj)/__divq.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=64
+$(obj)/__remq.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=64
+$(obj)/__divlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=32
+$(obj)/__remlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=32
+$(obj)/__divl.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=32
+$(obj)/__reml.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=32
+
+targets += $(div-objs:.o=.S) $(div-objs:.o=.ss)
diff --git a/usr/klibc/arch/alpha/MCONFIG b/usr/klibc/arch/alpha/MCONFIG
new file mode 100644
index 0000000..64847b7
--- /dev/null
+++ b/usr/klibc/arch/alpha/MCONFIG
@@ -0,0 +1,19 @@
+# -*- makefile -*-
+#
+# arch/alpha/MCONFIG
+#
+# Build configuration for this architecture
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 7 GB - normal binaries start at 4.5 GB, and the stack is below
+# the binary.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x1c0000000
+
+# Kernel uses our sa_restorer for signal return
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/alpha/README-gcc b/usr/klibc/arch/alpha/README-gcc
new file mode 100644
index 0000000..1d0052f
--- /dev/null
+++ b/usr/klibc/arch/alpha/README-gcc
@@ -0,0 +1,22 @@
+ The current Alpha chips don't provide hardware for integer
+ division. The C compiler expects the functions
+
+ __divqu: 64-bit unsigned long divide
+ __remqu: 64-bit unsigned long remainder
+ __divq/__remq: signed 64-bit
+ __divlu/__remlu: unsigned 32-bit
+ __divl/__reml: signed 32-bit
+
+ These are not normal C functions: instead of the normal calling
+ sequence, these expect their arguments in registers t10 and t11, and
+ return the result in t12 (aka pv). Register AT may be clobbered
+ (assembly temporary), anything else must be saved.
+
+ Furthermore, the return address is in t9 instead of ra.
+
+ Normal function Divide functions
+ --------------- ----------------
+ v0 ($0) t12/pv ($27)
+ a0 ($16) t10 ($24)
+ a1 ($17) t11 ($25)
+ ra ($26) t9 ($23)
diff --git a/usr/klibc/arch/alpha/crt0.S b/usr/klibc/arch/alpha/crt0.S
new file mode 100644
index 0000000..5e2babb
--- /dev/null
+++ b/usr/klibc/arch/alpha/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/alpha/crt0.S
+#
+
+ .text
+ .type _start,@function
+ .ent _start, 0
+ .globl _start
+_start:
+ .frame $30, 0, $26, 0
+ mov $31, $15
+ br $29, 1f
+1: ldgp $29, 0($29)
+ .prologue 0
+
+ lda $16, 0($30) # ELF data structure
+ lda $17, 0($0) # atexit pointer
+
+ jsr $26, __libc_init
+
+ .size _start,.-_start
+ .end _start
diff --git a/usr/klibc/arch/alpha/divide.c b/usr/klibc/arch/alpha/divide.c
new file mode 100644
index 0000000..c44254f
--- /dev/null
+++ b/usr/klibc/arch/alpha/divide.c
@@ -0,0 +1,59 @@
+#include <stdint.h>
+#include <asm/gentrap.h>
+#include <asm/pal.h>
+
+#if BITS == 64
+typedef uint64_t uint;
+typedef int64_t sint;
+#else
+typedef uint32_t uint;
+typedef int32_t sint;
+#endif
+
+#ifdef SIGNED
+typedef sint xint;
+#else
+typedef uint xint;
+#endif
+
+xint NAME(uint num, uint den)
+{
+ uint quot = 0, qbit = 1;
+ int minus = 0;
+ xint v;
+
+ if (den == 0) {
+ /* This is really $16, but $16 and $24 are exchanged by a script */
+ register unsigned long cause asm("$24") = GEN_INTDIV;
+ asm volatile ("call_pal %0"::"i" (PAL_gentrap), "r"(cause));
+ return 0; /* If trap returns... */
+ }
+#if SIGNED
+ if ((sint) (num ^ den) < 0)
+ minus = 1;
+ if ((sint) num < 0)
+ num = -num;
+ if ((sint) den < 0)
+ den = -den;
+#endif
+
+ /* Left-justify denominator and count shift */
+ while ((sint) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ v = (xint) (REM ? num : quot);
+ if (minus)
+ v = -v;
+ return v;
+}
diff --git a/usr/klibc/arch/alpha/pipe.S b/usr/klibc/arch/alpha/pipe.S
new file mode 100644
index 0000000..ee72413
--- /dev/null
+++ b/usr/klibc/arch/alpha/pipe.S
@@ -0,0 +1,38 @@
+#
+# arch/alpha/pipe.S
+#
+
+#
+# pipe() on alpha returns both file descriptors in registers --
+# $0 (v0) and $20 (a4) respectively. This is unlike any other system call,
+# as far as I can tell.
+#
+
+#include <asm/unistd.h>
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type pipe, @function
+ .ent pipe, 0
+ .globl pipe
+pipe:
+ .frame sp,0,ra,0
+ lda v0, __NR_pipe
+ callsys
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ lda v0, -1(zero)
+ stl a3, 0(a1)
+ ret zero,(ra),1
+1:
+ stl v0, 0(a0)
+ lda v0, 0
+ stl a4, 4(a0)
+ ret zero,(ra),1
+
+ .size pipe,.-pipe
+ .end pipe
diff --git a/usr/klibc/arch/alpha/setjmp.S b/usr/klibc/arch/alpha/setjmp.S
new file mode 100644
index 0000000..ed604bd
--- /dev/null
+++ b/usr/klibc/arch/alpha/setjmp.S
@@ -0,0 +1,75 @@
+#
+# setjmp.S
+#
+
+#
+# The jmp_buf looks like:
+#
+# s0..5
+# fp
+# ra
+# gp
+# sp
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type setjmp,@function
+ .ent setjmp, 0
+ .globl setjmp
+setjmp:
+ lda v0, 0(zero)
+ stq s0, 0(a0)
+ stq s1, 8(a0)
+ stq s2, 16(a0)
+ stq s3, 24(a0)
+ stq s4, 32(a0)
+ stq s5, 40(a0)
+ stq fp, 48(a0)
+ stq ra, 56(a0)
+ stq gp, 64(a0)
+ stq sp, 72(a0)
+ stt $f2, 80(a0)
+ stt $f3, 88(a0)
+ stt $f4, 96(a0)
+ stt $f5, 104(a0)
+ stt $f6, 112(a0)
+ stt $f7, 120(a0)
+ stt $f8, 128(a0)
+ stt $f9, 136(a0)
+ ret zero,(ra),1
+
+ .size setjmp,.-setjmp
+ .end setjmp
+
+ .type longjmp,@function
+ .ent longjmp, 0
+ .globl longjmp
+longjmp:
+ mov a1, v0
+ ldq s0, 0(a0)
+ ldq s1, 8(a0)
+ ldq s2, 16(a0)
+ ldq s3, 24(a0)
+ ldq s4, 32(a0)
+ ldq s5, 40(a0)
+ ldq fp, 48(a0)
+ ldq ra, 56(a0)
+ ldq gp, 64(a0)
+ ldq sp, 72(a0)
+ ldt $f2, 80(a0)
+ ldt $f3, 88(a0)
+ ldt $f4, 96(a0)
+ ldt $f5, 104(a0)
+ ldt $f6, 112(a0)
+ ldt $f7, 120(a0)
+ ldt $f8, 128(a0)
+ ldt $f9, 136(a0)
+ /* We're bound to get a mispredict here, but at least give us
+ a chance to get the return stack back in sync... */
+ ret zero,(ra),1
+
+ .size longjmp,.-longjmp
+ .end longjmp
diff --git a/usr/klibc/arch/alpha/sigaction.c b/usr/klibc/arch/alpha/sigaction.c
new file mode 100644
index 0000000..53e830b
--- /dev/null
+++ b/usr/klibc/arch/alpha/sigaction.c
@@ -0,0 +1,16 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+
+__extern void __sigreturn(void);
+__extern int ____rt_sigaction(int, const struct sigaction *, struct sigaction *,
+ size_t, void (*)(void));
+
+int __rt_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact, size_t size)
+{
+ return ____rt_sigaction(sig, act, oact, size, &__sigreturn);
+}
diff --git a/usr/klibc/arch/alpha/sigreturn.S b/usr/klibc/arch/alpha/sigreturn.S
new file mode 100644
index 0000000..a979b7a
--- /dev/null
+++ b/usr/klibc/arch/alpha/sigreturn.S
@@ -0,0 +1,18 @@
+/*
+ * arch/alpha/sigreturn.S
+ */
+
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ .text
+ .align 3
+ .type __sigreturn,@function
+ .ent __sigreturn,0
+ .globl __sigreturn
+__sigreturn:
+ mov sp,a0 # struct sigcontext on stack
+ lda v0,__NR_rt_sigreturn(zero)
+ callsys
+ .size __sigreturn,.-__sigreturn
+ .end __sigreturn
diff --git a/usr/klibc/arch/alpha/syscall.S b/usr/klibc/arch/alpha/syscall.S
new file mode 100644
index 0000000..ae69ef2
--- /dev/null
+++ b/usr/klibc/arch/alpha/syscall.S
@@ -0,0 +1,26 @@
+#
+# arch/alpha/syscall.S
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type __syscall_common,@function
+ .ent __syscall_common, 0
+ .globl __syscall_common
+__syscall_common:
+ .frame sp,0,ra,0
+ callsys
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ stl v0, 0(a1)
+ lda v0, -1(zero)
+1:
+ ret zero,(ra),1
+
+ .size __syscall_common,.-__syscall_common
+ .end __syscall_common
diff --git a/usr/klibc/arch/alpha/sysdual.S b/usr/klibc/arch/alpha/sysdual.S
new file mode 100644
index 0000000..03e719d
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysdual.S
@@ -0,0 +1,33 @@
+#
+# arch/alpha/sysdual.S
+#
+
+#
+# Some system calls have an alternate return value in r20 (a4).
+# This system call stub is for system calls where that is
+# the "real" return value.
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type __syscall_dual1,@function
+ .ent __syscall_dual1, 0
+ .globl __syscall_dual1
+__syscall_dual1:
+ .frame sp,0,ra,0
+ callsys
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ stl v0, 0(a1)
+ lda a4, -1(zero)
+1:
+ mov a4, v0
+ ret zero,(ra),1
+
+ .size __syscall_dual1,.-__syscall_dual1
+ .end __syscall_dual1
diff --git a/usr/klibc/arch/alpha/sysstub.ph b/usr/klibc/arch/alpha/sysstub.ph
new file mode 100644
index 0000000..08b97e8
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysstub.ph
@@ -0,0 +1,37 @@
+# -*- perl -*-
+#
+# arch/alpha/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On Alpha, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+#
+# A few system calls are dual-return with the second return value in
+# r20 (a4).
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ $stype = 'common' if ( $stype eq 'dual0' );
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "\n";
+ print OUT "\t.text\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.ent\t${fname}, 0\n"; # What is this?
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tlda\tv0, __NR_${sname}(zero)\n";
+ print OUT "\tbr __syscall_${stype}\n";
+ print OUT "\t.size\t${fname},.-${fname}\n";
+ print OUT "\t.end\t${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/arm/Kbuild b/usr/klibc/arch/arm/Kbuild
new file mode 100644
index 0000000..4946b6b
--- /dev/null
+++ b/usr/klibc/arch/arm/Kbuild
@@ -0,0 +1,13 @@
+#
+# klibc files for arm
+#
+
+klib-y := setjmp.o syscall.o vfork.o aeabi_nonsense.o
+
+klib-y += ../../libgcc/__udivmodsi4.o ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o ../../libgcc/__udivmoddi4.o
+klib-y += ../../libgcc/__clzsi2.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/arm/MCONFIG b/usr/klibc/arch/arm/MCONFIG
new file mode 100644
index 0000000..db5b14a
--- /dev/null
+++ b/usr/klibc/arch/arm/MCONFIG
@@ -0,0 +1,40 @@
+# -*- makefile -*-
+#
+# arch/arm/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+CPU_ARCH ?= armv4
+CPU_TUNE ?= strongarm
+
+KLIBCOPTFLAGS += -Os -march=$(CPU_ARCH) -mtune=$(CPU_TUNE)
+KLIBCBITSIZE = 32
+KLIBCREQFLAGS += -fno-exceptions
+KLIBCSTRIPFLAGS += -R .ARM.exidx
+
+ifeq ($(CONFIG_KLIBC_THUMB),y)
+CPU_ARCH := $(CPU_ARCH)t
+KLIBCREQFLAGS += -mthumb
+KLIBCREQFLAGS += -mabi=aapcs-linux
+else
+# Extra linkflags when building the shared version of the library
+ifeq ($(CONFIG_AEABI),y)
+KLIBCREQFLAGS += -mabi=aapcs-linux -mno-thumb-interwork
+else
+KLIBCREQFLAGS += -mabi=apcs-gnu -mno-thumb-interwork
+endif
+endif
+
+# Normal binaries start at 64 kiB. A32 branch instructions have a
+# range of ±32 MiB and T32 branch instructions only ±16 MiB, so we
+# have to put klibc.so in that range. Putting it close above the
+# executable can cause breakage, so instead swap them around:
+# klibc.so at 2 MiB and executable at 4 MiB.
+KLIBCLDFLAGS = $(LD_IMAGE_BASE_OPT) 0x400000
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x200000
+
+# Kernel uses dedicated page or vDSO for signal return since 2.6.13
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/arm/__muldi3.c b/usr/klibc/arch/arm/__muldi3.c
new file mode 100644
index 0000000..3fdeb2b
--- /dev/null
+++ b/usr/klibc/arch/arm/__muldi3.c
@@ -0,0 +1,15 @@
+#include <stdint.h>
+
+uint64_t __muldi3(uint64_t a, uint64_t b)
+{
+ uint32_t al = (uint32_t)a;
+ uint32_t ah = (uint32_t)(a >> 32);
+ uint32_t bl = (uint32_t)b;
+ uint32_t bh = (uint32_t)(b >> 32);
+ uint64_t v;
+
+ v = (uint64_t)al * bl;
+ v += (uint64_t)(al*bh+ah*bl) << 32;
+
+ return v;
+}
diff --git a/usr/klibc/arch/arm/aeabi_nonsense.S b/usr/klibc/arch/arm/aeabi_nonsense.S
new file mode 100644
index 0000000..c69eb11
--- /dev/null
+++ b/usr/klibc/arch/arm/aeabi_nonsense.S
@@ -0,0 +1,9 @@
+ .text
+ .globl __aeabi_unwind_cpp_pr0
+__aeabi_unwind_cpp_pr0:
+ .globl __aeabi_unwind_cpp_pr1
+__aeabi_unwind_cpp_pr1:
+ .globl __aeabi_unwind_cpp_pr2
+__aeabi_unwind_cpp_pr2:
+ .globl __aeabi_unwind_cpp_pr3
+__aeabi_unwind_cpp_pr3:
diff --git a/usr/klibc/arch/arm/crt0.S b/usr/klibc/arch/arm/crt0.S
new file mode 100644
index 0000000..1e81f8e
--- /dev/null
+++ b/usr/klibc/arch/arm/crt0.S
@@ -0,0 +1,23 @@
+#
+# arch/arm/crt0.S
+#
+# void _start(void)
+# {
+# __libc_init(elf_structure, atexit_ptr);
+# }
+#
+
+ .text
+ .balign 4
+ .type _start,#function
+ .globl _start
+
+#ifdef __thumb__
+ .thumb_func
+#endif
+
+_start: mov r0, sp
+ mov r1, #0
+ bl __libc_init
+
+ .size _start,.-_start
diff --git a/usr/klibc/arch/arm/setjmp.S b/usr/klibc/arch/arm/setjmp.S
new file mode 100644
index 0000000..9f96274
--- /dev/null
+++ b/usr/klibc/arch/arm/setjmp.S
@@ -0,0 +1,108 @@
+#
+# arch/arm/setjmp.S
+#
+# setjmp/longjmp for the ARM architecture
+#
+
+#include <klibc/asmmacros.h>
+
+#ifndef __thumb__
+
+#
+# "Pure ARM" version
+#
+# The jmp_buf is assumed to contain the following, in order:
+# r4
+# r5
+# r6
+# r7
+# r8
+# r9
+# r10
+# fp
+# sp
+# lr
+#
+
+ .text
+ .balign 4
+ .globl setjmp
+ .type setjmp, #function
+setjmp:
+ stmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+ mov r0, #0
+ BX(lr)
+ .size setjmp,.-setjmp
+
+ .text
+ .balign 4
+ .globl longjmp
+ .type longjmp, #function
+longjmp:
+ ldmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr}
+ movs r0, r1
+ moveq r0, #1
+ BX(lr)
+ .size longjmp,.-longjmp
+
+#else /* __thumb__ */
+
+#
+# Thumb version
+#
+# The jmp_buf is assumed to contain the following, in order:
+# lr
+# r4
+# r5
+# r6
+# r7
+# r8
+# r9
+# r10
+# fp
+# sp
+#
+
+ .text
+ .balign 4
+ .globl setjmp
+ .type setjmp, #function
+ .thumb_func
+setjmp:
+ mov r2, r0
+ mov r3, lr
+ stmia r0!, {r3, r4, r5, r6, r7}
+ mov r3, r8
+ mov r4, r9
+ mov r5, r10
+ mov r6, fp
+ mov r7, sp
+ stmia r0!, {r3, r4, r5, r6, r7}
+ /* Do not trash r4 .. r7 */
+ ldmia r2!, {r3, r4, r5, r6, r7}
+ mov r0, #0
+ BX(lr)
+ .size setjmp,.-setjmp
+
+ .text
+ .balign 4
+ .globl longjmp
+ .type longjmp, #function
+ .thumb_func
+longjmp:
+ mov r2, r0
+ add r0, #5*4
+ ldmia r0!, {r3, r4, r5, r6, r7}
+ mov r8, r3
+ mov r9, r4
+ mov r10, r5
+ mov fp, r6
+ mov sp, r7
+ ldmia r2!, {r3, r4, r5, r6, r7}
+ mov r0, r1
+ bne 1f
+ mov r0, #1
+1: BX(r3)
+ .size longjmp,.-longjmp
+
+#endif /* __thumb__ */
diff --git a/usr/klibc/arch/arm/syscall.S b/usr/klibc/arch/arm/syscall.S
new file mode 100644
index 0000000..e5b04e2
--- /dev/null
+++ b/usr/klibc/arch/arm/syscall.S
@@ -0,0 +1,65 @@
+/*
+ * arch/arm/syscall.S
+ *
+ * System call common handling
+ */
+
+ .type __syscall_common,#function
+ .globl __syscall_common
+#ifndef __thumb__
+ /* ARM version - this is executed after the swi, unless
+ we are compiled in EABI mode */
+
+ .balign 4
+__syscall_common:
+#ifdef __ARM_EABI__
+ ldr r4, [sp,#16]
+ ldr r5, [sp,#20]
+ ldr r7, [lr]
+ swi 0
+#endif
+ cmn r0, #4096
+ rsbcs r2, r0, #0
+ ldrcs r3, 1f
+ mvncs r0, #0
+ strcs r2, [r3]
+#ifdef __ARM_EABI__
+ ldmfd sp!,{r4,r5,r7,pc}
+#else
+ ldmfd sp!,{r4,r5,pc}
+#endif
+
+ .balign 4
+1:
+ .word errno
+
+#else
+ /* Thumb version - must still load r4 and r5 and run swi */
+
+ .thumb_func
+ .balign 2
+__syscall_common:
+ mov r7, lr
+ ldr r4, [sp,#16]
+ sub r7, #1 /* Remove the Thumb bit */
+ ldr r5, [sp,#20]
+ ldrh r7, [r7]
+ swi 0
+ ldr r1, 2f
+ cmp r0, r1
+ bcc 1f
+ ldr r1, 3f
+ neg r2, r0
+ mov r0, #1
+ str r2, [r1]
+ neg r0, r0
+1:
+ pop {r4,r5,r7,pc}
+
+ .balign 4
+2:
+ .word -4095
+3:
+ .word errno
+
+#endif
diff --git a/usr/klibc/arch/arm/sysstub.ph b/usr/klibc/arch/arm/sysstub.ph
new file mode 100644
index 0000000..1a4eca0
--- /dev/null
+++ b/usr/klibc/arch/arm/sysstub.ph
@@ -0,0 +1,58 @@
+# -*- perl -*-
+#
+# arch/arm/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "#include <klibc/asmmacros.h>\n";
+
+ print OUT " .text\n";
+ print OUT " .type ${fname}, #function\n";
+ print OUT " .globl ${fname}\n";
+
+ print OUT "#ifndef __thumb__\n";
+
+ print OUT "#ifndef __ARM_EABI__\n";
+
+ # ARM version first
+ print OUT " .balign 4\n";
+ print OUT "${fname}:\n";
+ print OUT " stmfd sp!,{r4,r5,lr}\n";
+ print OUT " ldr r4,[sp,#12]\n";
+ print OUT " ldr r5,[sp,#16]\n";
+ print OUT " swi # __NR_${sname}\n";
+ print OUT " b __syscall_common\n";
+
+ print OUT "#else /* __ARM_EABI__ */\n";
+
+ # ARM EABI version
+ print out " .balign 4\n";
+ print OUT "${fname}:\n";
+ print OUT " stmfd sp!,{r4,r5,r7,lr}\n";
+ print OUT " bl __syscall_common\n";
+ print OUT " .word __NR_${sname}\n";
+
+ print OUT "#endif /* __ARM_EABI__ */\n";
+ print OUT "#else /* __thumb__ */\n";
+
+ # Thumb version
+ print OUT " .balign 8\n";
+ print OUT " .thumb_func\n";
+ print OUT "${fname}:\n";
+ print OUT " push {r4,r5,r7,lr}\n";
+ print OUT " bl __syscall_common\n";
+ print OUT " .short __NR_${sname}\n";
+
+ print OUT "#endif /* __thumb__*/\n";
+
+ print OUT " .size ${fname},.-${fname}\n";
+}
+
+1;
diff --git a/usr/klibc/arch/arm/vfork.S b/usr/klibc/arch/arm/vfork.S
new file mode 100644
index 0000000..7130b65
--- /dev/null
+++ b/usr/klibc/arch/arm/vfork.S
@@ -0,0 +1,61 @@
+/*
+ * arch/arm/vfork.S
+ *
+ * vfork - nasty system call which must not use the stack.
+ */
+
+#include <klibc/asmmacros.h>
+#include <asm/unistd.h>
+
+ .type vfork,#function
+ .globl vfork
+#ifndef __thumb__
+
+ .balign 4
+vfork:
+#ifdef __ARM_EABI__
+ mov r3, r7
+ mov r7, # __NR_vfork
+ swi 0
+ mov r7, r3
+#else
+ swi # __NR_vfork
+#endif
+ cmn r0, #4096
+ rsbcs r2, r0, #0
+ ldrcs r3, 1f
+ mvncs r0, #0
+ strcs r2, [r3]
+ BX(lr)
+
+ .balign 4
+1:
+ .word errno
+
+#else
+
+ .thumb_func
+ .balign 2
+vfork:
+ mov r3, r7
+ mov r7, # __NR_vfork
+ swi 0
+ mov r7, r3
+ ldr r1, 2f
+ cmp r0, r1
+ bcc 1f
+ ldr r1, 3f
+ neg r2, r0
+ mov r0, #1
+ str r2, [r1]
+ neg r0, r0
+1:
+ BX(lr)
+
+ .balign 4
+2:
+ .word -4095
+3:
+ .word errno
+
+#endif
diff --git a/usr/klibc/arch/arm64/Kbuild b/usr/klibc/arch/arm64/Kbuild
new file mode 100644
index 0000000..f8643b5
--- /dev/null
+++ b/usr/klibc/arch/arm64/Kbuild
@@ -0,0 +1,7 @@
+
+# klibc files for arm64
+#
+
+klib-y := setjmp.o syscall.o vfork.o
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/arm64/MCONFIG b/usr/klibc/arch/arm64/MCONFIG
new file mode 100644
index 0000000..b90568e
--- /dev/null
+++ b/usr/klibc/arch/arm64/MCONFIG
@@ -0,0 +1,27 @@
+# -*- makefile -*-
+#
+# arch/arm64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+CPU_ARCH ?= armv8-a
+CPU_TUNE ?= generic
+
+KLIBCOPTFLAGS += -g -Os -march=$(CPU_ARCH) -mtune=$(CPU_TUNE)
+KLIBCBITSIZE = 64
+KLIBCREQFLAGS += -fno-exceptions -mgeneral-regs-only
+KLIBCLDFLAGS = $(LD_IMAGE_BASE_OPT) 0x00400000
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+
+# On arm64, binaries are normally loaded at 4MB. Place klibc.so
+# a little before that at 2MB to prevent overlap.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x0200000
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/arm64/crt0.S b/usr/klibc/arch/arm64/crt0.S
new file mode 100644
index 0000000..0b2dd32
--- /dev/null
+++ b/usr/klibc/arch/arm64/crt0.S
@@ -0,0 +1,19 @@
+#
+# arch/arm64/crt0.S
+#
+# void _start(void)
+# {
+# __libc_init(elf_structure, atexit_ptr);
+# }
+#
+
+ .text
+ .balign 8
+ .type _start,#function
+ .globl _start
+
+_start:
+ mov x0, sp
+ mov x1, #0
+ bl __libc_init
+ .size _start,.-_start
diff --git a/usr/klibc/arch/arm64/setjmp.S b/usr/klibc/arch/arm64/setjmp.S
new file mode 100644
index 0000000..284e328
--- /dev/null
+++ b/usr/klibc/arch/arm64/setjmp.S
@@ -0,0 +1,45 @@
+#
+# arch/arm64/setjmp.S
+#
+# setjmp/longjmp for arm64
+#
+
+# we specify -mgeneral-regs-only as a build flag thus do not need to
+# save d8-d15
+
+ .text
+ .balign 8
+ .globl setjmp
+ .type setjmp, #function
+setjmp:
+ mov x1, sp
+ stp x19, x20, [x0, #0]
+ stp x21, x22, [x0, #16]
+ stp x23, x24, [x0, #32]
+ stp x25, x26, [x0, #48]
+ stp x27, x28, [x0, #64]
+ stp x29, x30, [x0, #80]
+ str x1, [x0, #96]
+ mov x0, #0 /* set the return value of setjmp */
+ br x30
+ .size setjmp,.-setjmp
+
+ .text
+ .balign 8
+ .globl longjmp
+ .type longjmp, #function
+longjmp:
+ ldp x19, x20, [x0, #0]
+ ldp x21, x22, [x0, #16]
+ ldp x23, x24, [x0, #32]
+ ldp x25, x26, [x0, #48]
+ ldp x27, x28, [x0, #64]
+ ldp x29, x30, [x0, #80]
+ ldr x2, [x0, #96]
+ mov sp, x2
+ mov x0, x1
+ cbnz x1, 1f
+ mov x0, #1
+1:
+ br x30
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/arm64/syscall.S b/usr/klibc/arch/arm64/syscall.S
new file mode 100644
index 0000000..e100412
--- /dev/null
+++ b/usr/klibc/arch/arm64/syscall.S
@@ -0,0 +1,25 @@
+/*
+ * arch/arm64/syscall.S
+ *
+ * System call common handling - if the return
+ * value from the system call is negative, then
+ * extract the magnitude and return it as errno and
+ * return -1, if the return value is 0 that is
+ * success case.
+ */
+
+ .type __syscall_common,#function
+ .globl __syscall_common
+ .balign 8
+
+__syscall_common:
+ cmp x0, #0x0
+ b.ge 2f
+ neg x0, x0
+ ldr x8, 1f
+ str w0, [x8]
+ mov x0, #-1
+2:
+ ret
+1:
+ .dword errno
diff --git a/usr/klibc/arch/arm64/sysstub.ph b/usr/klibc/arch/arm64/sysstub.ph
new file mode 100644
index 0000000..095b1e8
--- /dev/null
+++ b/usr/klibc/arch/arm64/sysstub.ph
@@ -0,0 +1,24 @@
+# -*- perl -*-
+#
+# arch/arm64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT " .text\n";
+ print OUT " .type ${fname}, #function\n";
+ print OUT " .globl ${fname}\n";
+ print OUT " .balign 8\n";
+ print OUT "${fname}:\n";
+ print OUT " mov w8,__NR_${sname}\n";
+ print OUT " svc 0\n";
+ print OUT " b __syscall_common\n";
+ print OUT " .size ${fname},.-${fname}\n";
+}
+
+1;
diff --git a/usr/klibc/arch/arm64/vfork.S b/usr/klibc/arch/arm64/vfork.S
new file mode 100644
index 0000000..c30b2a0
--- /dev/null
+++ b/usr/klibc/arch/arm64/vfork.S
@@ -0,0 +1,33 @@
+/*
+ * arch/arm64/vfork.S
+ *
+ * vfork - a system call which must not use the stack.
+ */
+
+#include <asm/unistd.h>
+
+ .type vfork,#function
+ .globl vfork
+ .balign 8
+
+vfork:
+ /* Prepare for the system call */
+ /* 1. Push the function pointer and argument location
+ on to the child process stack */
+ /* 2. Gather the Flags */
+ /* New sp is already in x1. */
+ mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+ mov x1, sp
+ mov w8,__NR_clone
+ svc 0
+ cmp x0, #0x0
+ b.ge 2f
+ neg x0, x0
+ ldr x8, 1f
+ str x0, [x8]
+ mov x0, #-1
+2:
+ ret
+1:
+ .dword errno
+ .size vfork,.-vfork
diff --git a/usr/klibc/arch/i386/Kbuild b/usr/klibc/arch/i386/Kbuild
new file mode 100644
index 0000000..de237be
--- /dev/null
+++ b/usr/klibc/arch/i386/Kbuild
@@ -0,0 +1,17 @@
+#
+# klibc .o files for i386
+#
+
+klib-y := setjmp.o syscall.o varsyscall.o
+klib-y += open.o openat.o vfork.o
+klib-y += libgcc/__ashldi3.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o
+klib-y += libgcc/__muldi3.o libgcc/__negdi2.o
+
+klib-y += ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/i386/MCONFIG b/usr/klibc/arch/i386/MCONFIG
new file mode 100644
index 0000000..e6f50dd
--- /dev/null
+++ b/usr/klibc/arch/i386/MCONFIG
@@ -0,0 +1,36 @@
+# -*- makefile -*-
+#
+# arch/i386/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+# Enable this to compile with register parameters; only safe for
+# gcc >= 3
+
+ifeq ($(CONFIG_REGPARM),y)
+REGPARM_OPT := -mregparm=3 -D_REGPARM=3
+endif
+
+gcc_align_option := $(call cc-option, \
+ -falign-functions=0 -falign-jumps=0 -falign-loops=0, \
+ -malign-functions=0 -malign-jumps=0 -malign-loops=0)
+gcc_m32_option := $(call cc-option, -m32, )
+
+KLIBCOPTFLAGS += -march=i386 -Os -g -fomit-frame-pointer $(gcc_align_option)
+KLIBCLDFLAGS = -m elf_i386
+KLIBCREQFLAGS += $(REGPARM_OPT)
+KLIBCARCHREQFLAGS += $(gcc_m32_option)
+
+KLIBCBITSIZE = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 96 MB - normal binaries start at 128 MB
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x06000000
+
+# Kernel uses dedicated page or vDSO for signal return since 2.5.55
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/i386/crt0.S b/usr/klibc/arch/i386/crt0.S
new file mode 100644
index 0000000..8c6635e
--- /dev/null
+++ b/usr/klibc/arch/i386/crt0.S
@@ -0,0 +1,31 @@
+#
+# arch/i386/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+ .text
+ .align 4
+ .type _start,@function
+ .globl _start
+_start:
+ # Save the address of the ELF argument array
+ movl %esp,%eax # Address of ELF arguments
+ # Set up a faux stack frame for the benefit of gdb
+ xorl %ebp,%ebp
+ push %ebp # Keep gdb from getting confused
+ push %ebp # Keep gdb from getting confused
+ # Push the arguments and called __libc_init()
+#ifndef _REGPARM
+ push %edx # atexit() function
+ push %eax # ELF array
+#endif
+ call __libc_init
+ # If __libc_init returns, problem...
+ hlt
+
+ .size _start, .-_start
diff --git a/usr/klibc/arch/i386/libgcc/__ashldi3.S b/usr/klibc/arch/i386/libgcc/__ashldi3.S
new file mode 100644
index 0000000..7344142
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__ashldi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__ashldi3.S
+ *
+ * 64-bit shl
+ */
+ .text
+ .align 4
+ .globl __ashldi3
+ .type __ashldi3,@function
+__ashldi3:
+#ifndef _REGPARM
+ movl 4(%esp),%eax
+ movl 8(%esp),%edx
+ movb 12(%esp),%cl
+#endif
+ cmpb $32,%cl
+ jae 1f
+
+ shldl %cl,%eax,%edx
+ shl %cl,%eax
+ ret
+
+1:
+ xorl %edx,%edx
+ shl %cl,%eax
+ xchgl %edx,%eax
+ ret
+
+ .size __ashldi3,.-__ashldi3
diff --git a/usr/klibc/arch/i386/libgcc/__ashrdi3.S b/usr/klibc/arch/i386/libgcc/__ashrdi3.S
new file mode 100644
index 0000000..7666eb2
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__ashrdi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__ashrdi3.S
+ *
+ * 64-bit sar
+ */
+ .text
+ .align 4
+ .globl __ashrdi3
+ .type __ashrdi3,@function
+__ashrdi3:
+#ifndef _REGPARM
+ movl 4(%esp),%eax
+ movl 8(%esp),%edx
+ movb 12(%esp),%cl
+#endif
+ cmpb $32,%cl
+ jae 1f
+
+ shrdl %cl,%edx,%eax
+ sarl %cl,%edx
+ ret
+
+1:
+ sarl %cl,%edx
+ movl %edx,%eax
+ cdq
+ ret
+
+ .size __ashrdi3,.-__ashrdi3
diff --git a/usr/klibc/arch/i386/libgcc/__lshrdi3.S b/usr/klibc/arch/i386/libgcc/__lshrdi3.S
new file mode 100644
index 0000000..6a63c52
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__lshrdi3.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__lshrdi3.S
+ *
+ * 64-bit shr
+ */
+ .text
+ .align 4
+ .globl __lshrdi3
+ .type __lshrdi3,@function
+__lshrdi3:
+#ifndef _REGPARM
+ movl 4(%esp),%eax
+ movl 8(%esp),%edx
+ movb 12(%esp),%cl
+#endif
+ cmpb $32,%cl
+ jae 1f
+
+ shrdl %cl,%edx,%eax
+ shrl %cl,%edx
+ ret
+
+1:
+ shrl %cl,%edx
+ xorl %eax,%eax
+ xchgl %edx,%eax
+ ret
+
+ .size __lshrdi3,.-__lshrdi3
diff --git a/usr/klibc/arch/i386/libgcc/__muldi3.S b/usr/klibc/arch/i386/libgcc/__muldi3.S
new file mode 100644
index 0000000..472c7cc
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__muldi3.S
@@ -0,0 +1,34 @@
+/*
+ * arch/i386/libgcc/__muldi3.S
+ *
+ * 64*64 = 64 bit unsigned multiplication
+ */
+
+ .text
+ .align 4
+ .globl __muldi3
+ .type __muldi3,@function
+__muldi3:
+ push %esi
+#ifndef _REGPARM
+ movl 8(%esp),%eax
+ movl %eax,%esi
+ movl 16(%esp),%ecx
+ mull %ecx
+ imull 12(%esp),%ecx
+ imull 20(%esp),%esi
+ addl %ecx,%edx
+ addl %esi,%edx
+#else
+ movl %eax,%esi
+ push %edx
+ mull %ecx
+ imull 8(%esp),%esi
+ addl %esi,%edx
+ pop %esi
+ imull %esi,%ecx
+ addl %ecx,%edx
+#endif
+ pop %esi
+ ret
+ .size __muldi3,.-__muldi3
diff --git a/usr/klibc/arch/i386/libgcc/__negdi2.S b/usr/klibc/arch/i386/libgcc/__negdi2.S
new file mode 100644
index 0000000..147ad94
--- /dev/null
+++ b/usr/klibc/arch/i386/libgcc/__negdi2.S
@@ -0,0 +1,21 @@
+/*
+ * arch/i386/libgcc/__negdi2.S
+ *
+ * 64-bit negation
+ */
+
+ .text
+ .align 4
+ .globl __negdi2
+ .type __negdi2,@function
+__negdi2:
+#ifndef _REGPARM
+ movl 4(%esp),%eax
+ movl 8(%esp),%edx
+#endif
+ negl %edx
+ negl %eax
+ sbbl $0,%edx
+ ret
+
+ .size __negdi2,.-__negdi2
diff --git a/usr/klibc/arch/i386/open.S b/usr/klibc/arch/i386/open.S
new file mode 100644
index 0000000..7cd136c
--- /dev/null
+++ b/usr/klibc/arch/i386/open.S
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/open.S
+ *
+ * Handle the open() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE 0100000
+
+ .globl open
+ .type open,@function
+
+open:
+#ifdef _REGPARM
+ movl 4(%esp),%eax
+ movl 8(%esp),%edx
+ movl 12(%esp),%ecx
+ orl $O_LARGEFILE,%edx
+#else
+ orl $O_LARGEFILE,8(%esp)
+#endif
+ pushl $__NR_open
+ jmp __syscall_common
+
+ .size open,.-open
diff --git a/usr/klibc/arch/i386/openat.S b/usr/klibc/arch/i386/openat.S
new file mode 100644
index 0000000..2dfdfe2
--- /dev/null
+++ b/usr/klibc/arch/i386/openat.S
@@ -0,0 +1,26 @@
+/*
+ * arch/i386/openat.S
+ *
+ * Handle the openat() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE 0100000
+
+#ifdef __NR_openat /* Don't build if kernel headers too old */
+
+ .globl openat
+ .type openat,@function
+
+openat:
+ orl $O_LARGEFILE,12(%esp)
+ pushl $__NR_openat
+ jmp __syscall_varadic
+
+ .size openat,.-openat
+
+#endif
diff --git a/usr/klibc/arch/i386/setjmp.S b/usr/klibc/arch/i386/setjmp.S
new file mode 100644
index 0000000..b766792
--- /dev/null
+++ b/usr/klibc/arch/i386/setjmp.S
@@ -0,0 +1,58 @@
+#
+# arch/i386/setjmp.S
+#
+# setjmp/longjmp for the i386 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+# %ebx
+# %esp
+# %ebp
+# %esi
+# %edi
+# <return address>
+#
+
+ .text
+ .align 4
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+#ifdef _REGPARM
+ movl %eax,%edx
+#else
+ movl 4(%esp),%edx
+#endif
+ popl %ecx # Return address, and adjust the stack
+ xorl %eax,%eax # Return value
+ movl %ebx,(%edx)
+ movl %esp,4(%edx) # Post-return %esp!
+ pushl %ecx # Make the call/return stack happy
+ movl %ebp,8(%edx)
+ movl %esi,12(%edx)
+ movl %edi,16(%edx)
+ movl %ecx,20(%edx) # Return address
+ ret
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+#ifdef _REGPARM
+ xchgl %eax,%edx
+#else
+ movl 4(%esp),%edx # jmp_ptr address
+ movl 8(%esp),%eax # Return value
+#endif
+ movl (%edx),%ebx
+ movl 4(%edx),%esp
+ movl 8(%edx),%ebp
+ movl 12(%edx),%esi
+ movl 16(%edx),%edi
+ jmp *20(%edx)
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/i386/syscall.S b/usr/klibc/arch/i386/syscall.S
new file mode 100644
index 0000000..b7814e8
--- /dev/null
+++ b/usr/klibc/arch/i386/syscall.S
@@ -0,0 +1,82 @@
+/*
+ * arch/i386/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are on the stack; the system call number in %eax.
+ */
+
+#define ARG(n) (4*(n)+24)(%esp)
+#define SYSNO ARG(-2)
+
+ .text
+ .align 4
+ .globl __syscall_common
+ .type __syscall_common,@function
+__syscall_common:
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+
+#ifdef _REGPARM
+ xchgl %ecx,%edx
+ movl %eax,%ebx
+ movl SYSNO,%eax
+ movl ARG(0),%esi
+ movl ARG(1),%edi
+ movl ARG(2),%ebp
+#else
+ movl SYSNO,%eax
+ movl ARG(0),%ebx # Syscall arguments
+ movl ARG(1),%ecx
+ movl ARG(2),%edx
+ movl ARG(3),%esi
+ movl ARG(4),%edi
+ movl ARG(5),%ebp
+#endif
+ .globl __syscall_common_tail
+__syscall_common_tail:
+ call *__syscall_entry
+
+ cmpl $-4095,%eax
+
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %edx # Drop system call number
+
+ jb 1f
+
+ # Error return, must set errno
+ negl %eax
+ movl %eax,errno
+ orl $-1,%eax # Return -1
+
+1:
+ ret
+
+ .size __syscall_common,.-__syscall_common
+
+#ifndef _REGPARM
+
+ .globl __syscall_varadic
+ .type __syscall_varadic,@function
+__syscall_varadic = __syscall_common
+
+#endif
+
+ .align 4
+__syscall_int80:
+ int $0x80
+ ret
+ .type __syscall_int80,@function
+ .size __syscall_int80,.-__syscall_int80
+
+ .data
+ .align 4
+ .globl __syscall_entry
+__syscall_entry:
+ .long __syscall_int80
+ .size __syscall_entry,.-__syscall_entry
diff --git a/usr/klibc/arch/i386/sysstub.ph b/usr/klibc/arch/i386/sysstub.ph
new file mode 100644
index 0000000..e73a3ff
--- /dev/null
+++ b/usr/klibc/arch/i386/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/i386/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+
+ $stype = 'common' if ( $stype eq '' );
+
+ print OUT "\tpushl \$__NR_${sname}\n";
+ print OUT "\tjmp __syscall_$stype\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/i386/varsyscall.S b/usr/klibc/arch/i386/varsyscall.S
new file mode 100644
index 0000000..e796a93
--- /dev/null
+++ b/usr/klibc/arch/i386/varsyscall.S
@@ -0,0 +1,37 @@
+/*
+ * arch/i386/varsyscall.S
+ *
+ * Common tail-handling code for varadic system calls (which always
+ * use the cdecl convention.)
+ *
+ * The arguments are on the stack; the system call number in %eax.
+ */
+
+#ifdef _REGPARM
+
+#define ARG(n) (4*n+24)(%esp)
+#define SYSNO ARG(-2)
+
+ .text
+ .align 4
+ .globl __syscall_varadic
+ .type __syscall_varadic,@function
+__syscall_varadic:
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+
+ movl SYSNO,%eax
+ movl ARG(0),%ebx # Syscall arguments
+ movl ARG(1),%ecx
+ movl ARG(2),%edx
+ movl ARG(3),%esi
+ movl ARG(4),%edi
+ movl ARG(5),%ebp
+
+ jmp __syscall_common_tail
+
+ .size __syscall_varadic,.-__syscall_varadic
+
+#endif
diff --git a/usr/klibc/arch/i386/vfork.S b/usr/klibc/arch/i386/vfork.S
new file mode 100644
index 0000000..d32b9b9
--- /dev/null
+++ b/usr/klibc/arch/i386/vfork.S
@@ -0,0 +1,29 @@
+#
+# usr/klibc/arch/i386/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+# We *MUST* use int $0x80, because calling the vdso would screw up
+# our stack handling.
+#
+
+#include <asm/unistd.h>
+
+ .text
+ .align 4
+ .globl vfork
+ .type vfork, @function
+vfork:
+ popl %edx /* Return address */
+ movl $__NR_vfork, %eax
+ int $0x80 /* DO NOT call the vdso here! */
+ pushl %edx
+ cmpl $-4095, %eax
+ jae 1f
+ ret
+1:
+ negl %eax
+ movl %eax, errno
+ orl $-1, %eax
+ ret
diff --git a/usr/klibc/arch/ia64/Kbuild b/usr/klibc/arch/ia64/Kbuild
new file mode 100644
index 0000000..41b8ca0
--- /dev/null
+++ b/usr/klibc/arch/ia64/Kbuild
@@ -0,0 +1,13 @@
+#
+# klibc files for ia64
+#
+
+klib-y := vfork.o setjmp.o sigaction.o pipe.o syscall.o
+
+klib-y += ../../libgcc/__divdi3.o ../../libgcc/__divsi3.o
+klib-y += ../../libgcc/__udivdi3.o ../../libgcc/__udivsi3.o
+klib-y += ../../libgcc/__umodsi3.o ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmodsi4.o ../../libgcc/__udivmoddi4.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ia64/MCONFIG b/usr/klibc/arch/ia64/MCONFIG
new file mode 100644
index 0000000..db6a4ce
--- /dev/null
+++ b/usr/klibc/arch/ia64/MCONFIG
@@ -0,0 +1,17 @@
+# -*- makefile -*-
+#
+# arch/ia64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -mno-pic
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 64
+
+KLIBCSHAREDFLAGS = -T $(srctree)/$(src)/arch/$(KLIBCARCH)/klibc.ld
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/ia64/crt0.S b/usr/klibc/arch/ia64/crt0.S
new file mode 100644
index 0000000..2394cc4
--- /dev/null
+++ b/usr/klibc/arch/ia64/crt0.S
@@ -0,0 +1,23 @@
+
+#include <asm/fpu.h>
+
+ .align 32
+ .global _start
+
+ .proc _start
+ .type _start,@function
+_start:
+ .prologue
+ .save rp, r0
+
+ alloc r2 = ar.pfs,0,0,2,0
+ movl r3 = FPSR_DEFAULT
+ ;;
+ adds out0= 16,sp /* argc pointer */
+
+ .body
+ br.call.sptk.few rp = __libc_init
+ ;;
+ break 0 /* break miserably if we ever return */
+
+ .endp _start
diff --git a/usr/klibc/arch/ia64/klibc.ld b/usr/klibc/arch/ia64/klibc.ld
new file mode 100644
index 0000000..d203d0a
--- /dev/null
+++ b/usr/klibc/arch/ia64/klibc.ld
@@ -0,0 +1,267 @@
+/* Linker script for klibc.so. Whilst we can control text-segment for klibc.so
+ to not collide, the data segment is not controllable and hard-coded to start
+ at 0x6000000000000000 for position-dependent outputs, rather than simply
+ following on from the text segment like position-independent output or other
+ architectures. */
+/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
+ Copying and distribution of this script, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. */
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ /* Dynamic linker is normally placed in the 0x20..0 segment along with any
+ mmap'ed shared libraries. */
+ . = SEGMENT_START("text-segment", 0x2000000000000000) + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+ *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+ *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+ *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rel.plt :
+ {
+ *(.rel.plt)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ }
+ .rela.IA_64.pltoff : { *(.rela.IA_64.pltoff) }
+ .init :
+ {
+ KEEP (*(SORT_NONE(.init)))
+ } =0x00300000010070000002000001000400
+ .plt : { *(.plt) }
+ .iplt : { *(.iplt) }
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+ *(.text.exit .text.exit.*)
+ *(.text.startup .text.startup.*)
+ *(.text.hot .text.hot.*)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x00300000010070000002000001000400
+ .fini :
+ {
+ KEEP (*(SORT_NONE(.fini)))
+ } =0x00300000010070000002000001000400
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 :
+ {
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .opd : { *(.opd) }
+ .IA_64.unwind_info : { KEEP(*(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*)) }
+ .IA_64.unwind : { KEEP(*(.IA_64.unwind* .gnu.linkonce.ia64unw.*)) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
+ .gcc_except_table.*) }
+ .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
+ /* These sections are generated by the Sun/Oracle C++ compiler. */
+ .exception_ranges : ONLY_IF_RO { *(.exception_ranges
+ .exception_ranges*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
+ .gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
+ /* Thread Local Storage sections */
+ .tdata :
+ {
+ PROVIDE_HIDDEN (__tdata_start = .);
+ *(.tdata .tdata.* .gnu.linkonce.td.*)
+ }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*crtbegin?.o(.ctors))
+ /* We don't want to include the .ctor section from
+ the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*crtbegin?.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+ .IA_64.pltoff : { *(.IA_64.pltoff) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ _edata = .; PROVIDE (edata = .);
+ . = .;
+ __bss_start = .;
+ .sbss :
+ {
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 64 / 8 : 1);
+ }
+ . = ALIGN(64 / 8);
+ . = SEGMENT_START("ldata-segment", .);
+ . = ALIGN(64 / 8);
+ _end = .; PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ /* DWARF Extension. */
+ .debug_macro 0 : { *(.debug_macro) }
+ .debug_addr 0 : { *(.debug_addr) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/usr/klibc/arch/ia64/pipe.S b/usr/klibc/arch/ia64/pipe.S
new file mode 100644
index 0000000..ae31a3a
--- /dev/null
+++ b/usr/klibc/arch/ia64/pipe.S
@@ -0,0 +1,27 @@
+#include <asm/unistd.h>
+ .align 32
+ .proc pipe
+ .global pipe
+pipe:
+ alloc r16 = ar.pfs, 1, 0, 8, 0
+ mov r33 = r32
+ mov r15=__NR_pipe
+ ;;
+ break 0x100000 // Do the syscall
+ ;;
+
+ cmp.ne p6, p7 = -1, r10
+ mov r15 = r0
+ ;;
+(p6) st4 [r32] = r8, 4
+
+(p7) movl r14 = errno
+(p7) addl r15 = -1, r0
+ ;;
+(p6) st4 [r32] = r9
+
+(p7) st4 [r14] = r8
+
+ mov r8 = r15
+ br.ret.sptk.many b0
+ .endp pipe
diff --git a/usr/klibc/arch/ia64/setjmp.S b/usr/klibc/arch/ia64/setjmp.S
new file mode 100644
index 0000000..ab1cea2
--- /dev/null
+++ b/usr/klibc/arch/ia64/setjmp.S
@@ -0,0 +1,343 @@
+/*
+ * IA-64 specific setjmp/longjmp routines
+ *
+ * Inspired by setjmp.s from the FreeBSD kernel.
+ */
+
+#define J_UNAT 0
+#define J_NATS 0x8
+#define J_PFS 0x10
+#define J_BSP 0x18
+#define J_RNAT 0x20
+#define J_PREDS 0x28
+#define J_LC 0x30
+#define J_R4 0x38
+#define J_R5 0x40
+#define J_R6 0x48
+#define J_R7 0x50
+#define J_SP 0x58
+#define J_F2 0x60
+#define J_F3 0x70
+#define J_F4 0x80
+#define J_F5 0x90
+#define J_F16 0xa0
+#define J_F17 0xb0
+#define J_F18 0xc0
+#define J_F19 0xd0
+#define J_F20 0xe0
+#define J_F21 0xf0
+#define J_F22 0x100
+#define J_F23 0x110
+#define J_F24 0x120
+#define J_F25 0x130
+#define J_F26 0x140
+#define J_F27 0x150
+#define J_F28 0x160
+#define J_F29 0x170
+#define J_F30 0x180
+#define J_F31 0x190
+#define J_FPSR 0x1a0
+#define J_B0 0x1a8
+#define J_B1 0x1b0
+#define J_B2 0x1b8
+#define J_B3 0x1c0
+#define J_B4 0x1c8
+#define J_B5 0x1d0
+#define J_SIGMASK 0x1d8
+#define J_SIGSET 0x1e0
+#define J_GP 0x1f0
+
+// 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
+//
+ .align 32
+ .global setjmp
+ .proc setjmp
+setjmp:
+ //
+ // Make sure buffer is aligned at 16byte boundary
+ //
+ add r10 = -0x10,r0 ;; // mask the lower 4 bits
+ and r32 = r32, r10;;
+ add r32 = 0x10, r32;; // move to next 16 byte boundary
+
+ 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
+ //
+ st8.spill [r11] = r4, J_R6-J_R4
+ ;;
+ st8.spill [r10] = r5, J_R7-J_R5
+ ;;
+ st8.spill [r11] = r6, J_SP-J_R6
+ ;;
+ st8.spill [r10] = r7, J_F3-J_R7
+ ;;
+ st8.spill [r11] = sp, J_F2-J_SP
+ ;;
+ //
+ // save spilled Unat and pfs registers
+ //
+ mov r2 = ar.unat // save Unat register after spill
+ ;;
+ st8 [r32] = r2, J_PFS-J_NATS // save unat for spilled regs
+ ;;
+ st8 [r32] = r15 // save pfs
+ //
+ // 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
+ //
+ // 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
+ .endp 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'.
+//
+
+ .align 32
+ .global longjmp
+ .proc longjmp
+longjmp:
+ //
+ // Make sure buffer is aligned at 16byte boundary
+ //
+ add r10 = -0x10,r0 ;; // mask the lower 4 bits
+ and r32 = r32, r10;;
+ add r32 = 0x10, r32;; // move to next 16 byte boundary
+
+ //
+ // caching the return value as we do invala in the end
+ //
+ mov r8 = r33 // return value
+
+ //
+ // get immediate context
+ //
+ mov r14 = ar.rsc // get user RSC conf
+ add r10 = J_PFS, r32 // get address of pfs
+ add r11 = J_NATS, r32
+ ;;
+ ld8 r15 = [r10], J_BSP-J_PFS // get pfs
+ ld8 r2 = [r11], J_LC-J_NATS // get unat for spilled regs
+ ;;
+ mov ar.unat = r2
+ ;;
+ ld8 r16 = [r10], J_PREDS-J_BSP // get backing store pointer
+ mov ar.rsc = r0 // put RSE in enforced lazy
+ mov ar.pfs = r15
+ ;;
+
+ //
+ // while returning from longjmp the BSPSTORE and BSP needs to be
+ // same and discard all the registers allocated after we did
+ // setjmp. Also, we need to generate the RNAT register since we
+ // did not flushed the RSE on setjmp.
+ //
+ mov r17 = ar.bspstore // get current BSPSTORE
+ ;;
+ cmp.ltu p6,p7 = r17, r16 // is it less than BSP of
+(p6) br.spnt.few .flush_rse
+ mov r19 = ar.rnat // get current RNAT
+ ;;
+ loadrs // invalidate dirty regs
+ br.sptk.many .restore_rnat // restore RNAT
+
+.flush_rse:
+ flushrs
+ ;;
+ mov r19 = ar.rnat // get current RNAT
+ mov r17 = r16 // current BSPSTORE
+ ;;
+.restore_rnat:
+ //
+ // check if RNAT is saved between saved BSP and curr BSPSTORE
+ //
+ mov r18 = 0x3f
+ ;;
+ dep r18 = r18,r16,3,6 // get RNAT address
+ ;;
+ cmp.ltu p8,p9 = r18, r17 // RNAT saved on RSE
+ ;;
+(p8) ld8 r19 = [r18] // get RNAT from RSE
+ ;;
+ mov ar.bspstore = r16 // set new BSPSTORE
+ ;;
+ mov ar.rnat = r19 // restore RNAT
+ 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 = [r32] // get user unat
+ ;;
+ mov b5 = r2
+ mov ar.unat = r21
+
+ //
+ // invalidate ALAT
+ //
+ invala ;;
+
+ br.ret.sptk b0
+ .endp longjmp
diff --git a/usr/klibc/arch/ia64/sigaction.c b/usr/klibc/arch/ia64/sigaction.c
new file mode 100644
index 0000000..3d2dbd4
--- /dev/null
+++ b/usr/klibc/arch/ia64/sigaction.c
@@ -0,0 +1,64 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+
+/* We use -mno-pic so our function pointers are straight to the function entry
+ point, but the kernel always expects a descriptor. Thus we create a fake
+ descriptor for each possible signal, update it, and pass that to the kernel
+ instead (the descriptor must remain valid after returning from sigaction
+ until it is replaced). */
+static struct {
+ uintptr_t entry;
+ uintptr_t gp;
+} signal_descriptors[_NSIG];
+
+__extern int ____rt_sigaction(int, const struct sigaction *, struct sigaction *,
+ size_t);
+
+int __rt_sigaction(int sig, struct sigaction *act,
+ struct sigaction *oact, size_t size)
+{
+ sigset_t signal_mask, old_signal_mask;
+ uintptr_t old_entry;
+ int rv;
+
+ if (sig < 0 || sig >= _NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Mask the signal to avoid races on access to its descriptor */
+ sigemptyset(&signal_mask);
+ sigaddset(&signal_mask, sig);
+ rv = sigprocmask(SIG_BLOCK, &signal_mask, &old_signal_mask);
+ if (rv)
+ return -1;
+
+ if (oact) {
+ old_entry = signal_descriptors[sig].entry;
+ }
+
+ if (act && act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) {
+ signal_descriptors[sig].entry = (uintptr_t)act->sa_handler;
+ act->sa_handler =
+ (__sighandler_t)(uintptr_t)&signal_descriptors[sig];
+ }
+
+ rv = ____rt_sigaction(sig, act, oact, size);
+
+ if (rv)
+ signal_descriptors[sig].entry = old_entry;
+
+ /* Restore signal mask */
+ (void)sigprocmask(SIG_SETMASK, &old_signal_mask, NULL);
+
+ if (oact && oact->sa_handler != SIG_IGN &&
+ oact->sa_handler != SIG_DFL) {
+ oact->sa_handler = (__sighandler_t)old_entry;
+ }
+
+ return rv;
+}
diff --git a/usr/klibc/arch/ia64/syscall.S b/usr/klibc/arch/ia64/syscall.S
new file mode 100644
index 0000000..155fdd8
--- /dev/null
+++ b/usr/klibc/arch/ia64/syscall.S
@@ -0,0 +1,18 @@
+#
+# arch/ia64/syscall.S
+#
+
+#include <asm/unistd.h>
+
+ .text
+ .align 32
+ .proc __syscall_error
+ .globl __syscall_error
+__syscall_error:
+ movl r2 = errno
+ ;;
+ st4 [r2] = r8
+ mov r8 = -1
+ br.ret.sptk.many b0
+ .size __syscall_error, .-__syscall_error
+ .endp __syscall_error
diff --git a/usr/klibc/arch/ia64/sysstub.ph b/usr/klibc/arch/ia64/sysstub.ph
new file mode 100644
index 0000000..8e686c6
--- /dev/null
+++ b/usr/klibc/arch/ia64/sysstub.ph
@@ -0,0 +1,29 @@
+# -*- perl -*-
+#
+# arch/ia64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.text\n";
+ print OUT "\t.align 32\n";
+ print OUT "\t.proc ${fname}\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tmov\tr15 = __NR_${sname}\n";
+ print OUT "\tbreak __BREAK_SYSCALL\n";
+ print OUT "\tcmp.eq p6,p0 = -1,r10\n";
+ print OUT "(p6)\tbr.few __syscall_error\n";
+ print OUT "\tbr.ret.sptk.many b0\n";
+ print OUT "\t.size\t${fname},.-${fname}\n";
+ print OUT "\t.endp\t${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/ia64/vfork.S b/usr/klibc/arch/ia64/vfork.S
new file mode 100644
index 0000000..e513188
--- /dev/null
+++ b/usr/klibc/arch/ia64/vfork.S
@@ -0,0 +1,37 @@
+/*
+ * ia64 specific vfork syscall
+ *
+ * Written By: Martin Hicks <mort@wildopensource.com>
+ *
+ */
+
+/* This syscall is a special case of the clone syscall */
+#include <asm/unistd.h>
+#include <asm/signal.h>
+
+/* These are redefined here because linux/sched.h isn't safe for
+ * inclusion in asm.
+ */
+#define CLONE_VM 0x00000100 /* set if VM shared between processes */
+#define CLONE_VFORK 0x00004000 /* set if parent wants the child to wake it up on exit */
+
+/* pid_t vfork(void) */
+/* Implemented as clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */
+
+ .align 32
+ .proc vfork
+ .global vfork
+vfork:
+ alloc r2=ar.pfs,0,0,2,0
+ mov r15=__NR_clone
+ mov out0=CLONE_VM|CLONE_VFORK|SIGCHLD
+ mov out1=0
+ break 0x100000 // Do the syscall
+ cmp.eq p7,p6 = -1,r10
+ ;;
+(p7) movl r14 = errno
+ ;;
+(p7) st4 [r14]=r8
+(p7) mov r8=-1
+ br.ret.sptk.many b0
+ .endp vfork
diff --git a/usr/klibc/arch/loongarch64/Kbuild b/usr/klibc/arch/loongarch64/Kbuild
new file mode 100644
index 0000000..60c7660
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/Kbuild
@@ -0,0 +1,7 @@
+#
+# klibc files for LoongArch64
+#
+
+klib-y := setjmp.o syscall.o
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/loongarch64/MCONFIG b/usr/klibc/arch/loongarch64/MCONFIG
new file mode 100644
index 0000000..0ef5eae
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/MCONFIG
@@ -0,0 +1,23 @@
+# -*- makefile -*-
+#
+# arch/loongarch64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE = 64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 4862 MB - normal binaries start at 4608 MB. Non-PIC jumps usually
+# use the BL instruction which requires a destination between -128M
+# to 128M. Since we can't put ourselves below the normal load
+# address, use the very top of the 128M region (minus 2MB)
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x127E00000
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/loongarch64/crt0.S b/usr/klibc/arch/loongarch64/crt0.S
new file mode 100644
index 0000000..cb3da66
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/crt0.S
@@ -0,0 +1,18 @@
+#
+# arch/loongarch64/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+#include <machine/asm.h>
+
+ENTRY(_start)
+ move $a0, $sp # Pointer to ELF entry structure
+ move $a1, $zero # No onexit pointer
+ bstrins.d $sp, $zero, 3, 0 # Align stack to 16 bytes
+ bl __libc_init
+END(_start)
diff --git a/usr/klibc/arch/loongarch64/setjmp.S b/usr/klibc/arch/loongarch64/setjmp.S
new file mode 100644
index 0000000..1177988
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/setjmp.S
@@ -0,0 +1,50 @@
+/*
+ * arch/loongarch64/setjmp.S
+ *
+ * setjmp/longjmp for the LoongArch64 architecture
+ *
+ * The jmp_buf is assumed to contain the following, in order:
+ * pc (ra)
+ * sp
+ * r21
+ * fp
+ * s0..s8
+ */
+
+#include <machine/asm.h>
+
+ENTRY(setjmp)
+ st.d $ra, $a0, 0
+ st.d $sp, $a0, 8
+ st.d $r21, $a0, 16
+ st.d $fp, $a0, 24
+ st.d $s0, $a0, 32
+ st.d $s1, $a0, 40
+ st.d $s2, $a0, 48
+ st.d $s3, $a0, 56
+ st.d $s4, $a0, 64
+ st.d $s5, $a0, 72
+ st.d $s6, $a0, 80
+ st.d $s7, $a0, 88
+ st.d $s8, $a0, 96
+ move $a0, $zero
+ jr $ra
+END(setjmp)
+
+ENTRY(longjmp)
+ ld.d $ra, $a0, 0
+ ld.d $sp, $a0, 8
+ ld.d $r21, $a0, 16
+ ld.d $fp, $a0, 24
+ ld.d $s0, $a0, 32
+ ld.d $s1, $a0, 40
+ ld.d $s2, $a0, 48
+ ld.d $s3, $a0, 56
+ ld.d $s4, $a0, 64
+ ld.d $s5, $a0, 72
+ ld.d $s6, $a0, 80
+ ld.d $s7, $a0, 88
+ ld.d $s8, $a0, 96
+ move $a0, $a1
+ jr $ra
+END(longjmp)
diff --git a/usr/klibc/arch/loongarch64/syscall.S b/usr/klibc/arch/loongarch64/syscall.S
new file mode 100644
index 0000000..9a2ed46
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/syscall.S
@@ -0,0 +1,13 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(__syscall_common)
+ syscall 0
+ li.w $t0, -4096
+ bleu $a0, $t0, 1f
+ sub.d $a0, $zero, $a0
+ la $t0, errno
+ st.d $a0, $t0, 0
+ li.w $a0, -1
+1: jr $ra
+END(__syscall_common)
diff --git a/usr/klibc/arch/loongarch64/sysstub.ph b/usr/klibc/arch/loongarch64/sysstub.ph
new file mode 100644
index 0000000..699bdc2
--- /dev/null
+++ b/usr/klibc/arch/loongarch64/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/loongarch64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On LoongArch64, most system calls follow the standard convention, with
+# the system call number in a7 and the return value in a0.
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "ENTRY(${fname})\n";
+ print OUT "\tli.w\t\$a7, __NR_${sname}\n";
+ print OUT "\tb\t__syscall_${stype}\n";
+ print OUT "END(${fname})\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/m68k/Kbuild b/usr/klibc/arch/m68k/Kbuild
new file mode 100644
index 0000000..d56ae0e
--- /dev/null
+++ b/usr/klibc/arch/m68k/Kbuild
@@ -0,0 +1,9 @@
+#
+# klibc files for m68k
+#
+
+klib-y := setjmp.o syscall.o vfork.o
+klib-y += open.o openat.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/m68k/MCONFIG b/usr/klibc/arch/m68k/MCONFIG
new file mode 100644
index 0000000..79bfbac
--- /dev/null
+++ b/usr/klibc/arch/m68k/MCONFIG
@@ -0,0 +1,23 @@
+# -*- makefile -*-
+#
+# arch/m68k/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2816 MB - normal binaries start at 2048 MB if I read the link
+# script right. Not sure if there is a fundamental reason
+# to not duck below the halfway point...
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0xb0000000
+
+# Kernel uses stack trampoline for signal return. Also m68k
+# page tables do not have an execute permission bit.
+KLIBCEXECSTACK := y
diff --git a/usr/klibc/arch/m68k/crt0.S b/usr/klibc/arch/m68k/crt0.S
new file mode 100644
index 0000000..fbf6f13
--- /dev/null
+++ b/usr/klibc/arch/m68k/crt0.S
@@ -0,0 +1,27 @@
+#
+# arch/m68k/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+ .text
+ .align 4
+ .type _start,@function
+ .globl _start
+_start:
+ # Zero out the frame pointer to be nice to the debugger
+ movea.l #0,%a6
+ # Save the address of the ELF argument array
+ move.l %a7, %d0
+ # Push a zero on the stack in lieu of atexit pointer
+ clr.l -(%sp)
+ # Push ELF argument pointer on the stack
+ move.l %d0, -(%a7)
+
+ jbsr __libc_init
+
+ .size _start, .-_start
diff --git a/usr/klibc/arch/m68k/open.S b/usr/klibc/arch/m68k/open.S
new file mode 100644
index 0000000..c9a7ee3
--- /dev/null
+++ b/usr/klibc/arch/m68k/open.S
@@ -0,0 +1,22 @@
+/*
+ * arch/m68k/open.S
+ *
+ * Handle the open() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE 0400000
+
+ .globl open
+ .type open,@function
+
+open:
+ or.l # O_LARGEFILE, 8(%sp)
+ move.l # __NR_open, %d0
+ br __syscall_common
+
+ .size open,.-open
diff --git a/usr/klibc/arch/m68k/openat.S b/usr/klibc/arch/m68k/openat.S
new file mode 100644
index 0000000..25d8a1a
--- /dev/null
+++ b/usr/klibc/arch/m68k/openat.S
@@ -0,0 +1,26 @@
+/*
+ * arch/m68k/openat.S
+ *
+ * Handle the openat() system call - oddball due to the varadic
+ * prototype, which forces the use of the cdecl calling convention,
+ * and the need for O_LARGEFILE.
+ */
+
+#include <asm/unistd.h>
+
+/* <asm/fcntl.h>, despite the name, isn't assembly-safe */
+#define O_LARGEFILE 0400000
+
+#ifdef __NR_openat /* Don't build if kernel headers too old */
+
+ .globl openat
+ .type openat,@function
+
+openat:
+ or.l # O_LARGEFILE, 12(%sp)
+ move.l # __NR_openat, %d0
+ br __syscall_common
+
+ .size openat,.-openat
+
+#endif
diff --git a/usr/klibc/arch/m68k/setjmp.S b/usr/klibc/arch/m68k/setjmp.S
new file mode 100644
index 0000000..1b3591e
--- /dev/null
+++ b/usr/klibc/arch/m68k/setjmp.S
@@ -0,0 +1,43 @@
+#
+# arch/m68k/setjmp.S
+#
+# setjmp/longjmp for the m68k architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+# %d2..%d7
+# %a2..%a7
+# return address
+#
+
+ .text
+ .align 2
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+ move.l (%sp)+, %d0 | Return address
+ movea.l (%sp), %a0 | Buffer address
+ | Postincrement mode is not permitted here...
+ movem.l %d2-%d7/%a2-%a7, (%a0)
+ move.l %d0, 48(%a0) | Return address
+ move.l %d0, -(%sp) | Restore return address
+ clr.l %d0 | Return value
+ movea.l %d0, %a0 | Redundant return...
+ rts
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 2
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ move.l 4(%sp), %a0 | Buffer address
+ move.l 8(%sp), %d0 | Return value
+ movem.l (%a0)+, %d2-%d7/%a2-%a7
+ movea.l (%a0), %a1
+ movea.l %d0, %a0 | Redundant return...
+ jmp.l (%a1)
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/m68k/syscall.S b/usr/klibc/arch/m68k/syscall.S
new file mode 100644
index 0000000..c909e2a
--- /dev/null
+++ b/usr/klibc/arch/m68k/syscall.S
@@ -0,0 +1,53 @@
+/*
+ * arch/m68k/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are on the stack; the system call number in %d0.
+ */
+
+ .text
+ .align 2
+ .globl __syscall_common
+ .type __syscall_common, @function
+__syscall_common:
+ /*
+ * According to eglibc, separate moves are faster than movem;
+ * speed is important and this code is not duplicated anyway,
+ * so we do the same here. We use %a1 as scratch register for
+ * saving; syscall arguments are to be in %d1 to %d5 and %a0.
+ */
+ move.l 24(%sp), %a0 /* orig.sp+24: arg 6 */
+ move.l %d5, -(%sp) /* push d5 (callee saved) */
+ move.l 24(%sp), %d5 /* orig.sp+20: arg 5 */
+ move.l %d4, -(%sp) /* push d4 (callee saved) */
+ move.l 24(%sp), %d4 /* orig.sp+16: arg 4 */
+ move.l %d3, -(%sp) /* push d3 (callee saved) */
+ move.l 24(%sp), %d3 /* orig.sp+12: arg 3 */
+ move.l %d2, %a1 /* save d2 (callee saved) in a1 */
+ move.l 20(%sp), %d2 /* orig.sp+8: arg 2 */
+ move.l 16(%sp), %d1 /* orig.sp+4: arg 1 */
+ trap #0
+ move.l %a1, %d2 /* restore d2 from a1 (scratch) */
+ move.l (%sp)+, %d3 /* pop d3..d5, see above */
+ move.l (%sp)+, %d4
+ move.l (%sp)+, %d5
+
+ /* syscall is done, result in %d0, registers are restored */
+ .globl __syscall_checkandout
+__syscall_checkandout:
+ /* now check for error */
+ cmp.l #-4095, %d0
+ bcs.l 1f /* jump if _not_ error */
+
+ /* prepare for error return */
+ neg.l %d0
+ move.l %d0, (errno)
+ move.l #-1, %d0
+ /* fallthrough into common return path */
+
+1: /* copy return value to %a0 for syscalls returning pointers */
+ move.l %d0, %a0
+ rts
+
+ .size __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/m68k/sysstub.ph b/usr/klibc/arch/m68k/sysstub.ph
new file mode 100644
index 0000000..78c239d
--- /dev/null
+++ b/usr/klibc/arch/m68k/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/m68k/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+
+ $stype = 'common' if ( $stype eq '' );
+
+ print OUT "\tmove.l\t# __NR_${sname}, %d0\n";
+ print OUT "\tbr\t__syscall_$stype\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/m68k/vfork.S b/usr/klibc/arch/m68k/vfork.S
new file mode 100644
index 0000000..98170a6
--- /dev/null
+++ b/usr/klibc/arch/m68k/vfork.S
@@ -0,0 +1,23 @@
+#
+# usr/klibc/arch/m68k/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+
+#include <asm/unistd.h>
+
+ .text
+ .align 2
+ .globl vfork
+ .type vfork, @function
+vfork:
+ move.l (%sp)+, %d1 /* Return address */
+ move.l # __NR_vfork, %d0
+ trap #0
+ move.l %d1, -(%sp) /* restore stack */
+
+ /* fallthrough into common code from syscall.S */
+ bra __syscall_checkandout
+
+ .size vfork, .-vfork
diff --git a/usr/klibc/arch/mips/Kbuild b/usr/klibc/arch/mips/Kbuild
new file mode 100644
index 0000000..972e450
--- /dev/null
+++ b/usr/klibc/arch/mips/Kbuild
@@ -0,0 +1,14 @@
+#
+# klibc files for mips
+#
+
+klib-y := pipe.o vfork.o setjmp.o syscall.o
+
+klib-y += ../../libgcc/__clzsi2.o ../../libgcc/__ashldi3.o
+klib-y += ../../libgcc/__ashrdi3.o ../../libgcc/__lshrdi3.o
+klib-y += ../../libgcc/__divdi3.o ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/mips/MCONFIG b/usr/klibc/arch/mips/MCONFIG
new file mode 100644
index 0000000..48cda8e
--- /dev/null
+++ b/usr/klibc/arch/mips/MCONFIG
@@ -0,0 +1,21 @@
+# -*- makefile -*-
+#
+# arch/mips/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -fno-pic -mno-abicalls -G 0
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2 MB - normal binaries start at 4 MB
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x00200000
+
+# Kernel uses vDSO for signal return since 2.6.34
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/mips/crt0.S b/usr/klibc/arch/mips/crt0.S
new file mode 100644
index 0000000..47d7d8f
--- /dev/null
+++ b/usr/klibc/arch/mips/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/mips/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+#include <machine/asm.h>
+
+NESTED(__start, 0, ra)
+ move a0, sp # Pointer to ELF entry structure
+ move a1, v0 # Kernel-provided atexit() pointer
+ and sp, -8 # Align stack to 8 bytes
+ subu sp, 16 # Allocate 16 bytes for function call
+
+ jal __libc_init
+ teq zero, zero # Crash if we return
+
+ END(__start)
diff --git a/usr/klibc/arch/mips/pipe.S b/usr/klibc/arch/mips/pipe.S
new file mode 100644
index 0000000..932fc08
--- /dev/null
+++ b/usr/klibc/arch/mips/pipe.S
@@ -0,0 +1,15 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+LEAF(pipe)
+ li v0, __NR_pipe
+ syscall
+ bnez a3, 1f
+ sw v0, (a0)
+ sw v1, 4(a0)
+ li v0, 0
+ b 2f
+1: sw v0, errno
+ li v0, -1
+2: jr ra
+ END(pipe)
diff --git a/usr/klibc/arch/mips/setjmp.S b/usr/klibc/arch/mips/setjmp.S
new file mode 100644
index 0000000..9145dbc
--- /dev/null
+++ b/usr/klibc/arch/mips/setjmp.S
@@ -0,0 +1,50 @@
+#
+# arch/mips/setjmp.S
+#
+# setjmp/longjmp for the MIPS architecture
+#
+# The jmp_buf is assumed to contain the following, in order:
+# s0..s7
+# gp
+# sp
+# s8
+# ra
+#
+
+#include <machine/asm.h>
+
+LEAF(setjmp)
+ sw s0, 0(a0)
+ sw s1, 4(a0)
+ sw s2, 8(a0)
+ sw s3, 12(a0)
+ sw s4, 16(a0)
+ sw s5, 20(a0)
+ sw s6, 24(a0)
+ sw s7, 28(a0)
+ sw gp, 32(a0)
+ sw sp, 36(a0)
+ sw s8, 40(a0)
+ sw ra, 44(a0)
+ move v0,zero
+ jr ra
+
+ END(setjmp)
+
+LEAF(longjmp)
+ lw s0, 0(a0)
+ lw s1, 4(a0)
+ lw s2, 8(a0)
+ lw s3, 12(a0)
+ lw s4, 16(a0)
+ lw s5, 20(a0)
+ lw s6, 24(a0)
+ lw s7, 28(a0)
+ lw gp, 32(a0)
+ lw sp, 36(a0)
+ lw s8, 40(a0)
+ lw ra, 44(a0)
+ move v0,a1
+ jr ra
+
+ END(longjmp)
diff --git a/usr/klibc/arch/mips/syscall.S b/usr/klibc/arch/mips/syscall.S
new file mode 100644
index 0000000..a5cc73d
--- /dev/null
+++ b/usr/klibc/arch/mips/syscall.S
@@ -0,0 +1,11 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+
+LEAF(__syscall_common)
+ syscall
+ beqz a3, 1f
+ sw v0, errno
+ li v0, -1
+1: jr ra
+ END(__syscall_common)
diff --git a/usr/klibc/arch/mips/sysstub.ph b/usr/klibc/arch/mips/sysstub.ph
new file mode 100644
index 0000000..a3475b7
--- /dev/null
+++ b/usr/klibc/arch/mips/sysstub.ph
@@ -0,0 +1,27 @@
+# -*- perl -*-
+#
+# arch/mips/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On MIPS, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "LEAF(${fname})\n";
+ print OUT "\t li\tv0, __NR_${sname}\n";
+ print OUT "\tj\t__syscall_${stype}\n";
+ print OUT "\tEND(${fname})\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/mips/vfork.S b/usr/klibc/arch/mips/vfork.S
new file mode 100644
index 0000000..ae36d5f
--- /dev/null
+++ b/usr/klibc/arch/mips/vfork.S
@@ -0,0 +1,14 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+#define CLONE_VM 0x00000100
+#define CLONE_VFORK 0x00004000
+#define SIGCHLD 18
+
+
+LEAF(vfork)
+ li a0, CLONE_VFORK | CLONE_VM | SIGCHLD
+ li a1, 0
+ li v0, __NR_clone
+ j __syscall_common
+ END(vfork)
diff --git a/usr/klibc/arch/mips64/Kbuild b/usr/klibc/arch/mips64/Kbuild
new file mode 100644
index 0000000..6fe3b53
--- /dev/null
+++ b/usr/klibc/arch/mips64/Kbuild
@@ -0,0 +1,14 @@
+#
+# klibc files for mips64
+#
+
+klib-y := ../mips/pipe.o ../mips/vfork.o setjmp.o ../mips/syscall.o
+
+klib-y += ../../libgcc/__clzsi2.o ../../libgcc/__ashldi3.o
+klib-y += ../../libgcc/__ashrdi3.o ../../libgcc/__lshrdi3.o
+klib-y += ../../libgcc/__divdi3.o ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/mips64/MCONFIG b/usr/klibc/arch/mips64/MCONFIG
new file mode 100644
index 0000000..e078dad
--- /dev/null
+++ b/usr/klibc/arch/mips64/MCONFIG
@@ -0,0 +1,34 @@
+# -*- makefile -*-
+#
+# arch/mips64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -fno-pic -mno-abicalls -G 0
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture.
+# Normal binaries start at 0x120000000 (4608 MiB).
+# * On R5 and earlier, non-PIC jumps usually use the JAL instruction
+# which requires a destination within the same 256 MiB aligned
+# region. Since we can't put ourselves below the normal load
+# address, use the very top of the 256 MiB region (minus 2 MiB).
+# * On R6, non-PIC jumps may use either the JAL instruction or the
+# BALC instruction which requires a destination within ±128 MiB. Put
+# ourselves just under 128 MiB above the executable base address.
+ifneq ($(CONFIG_KLIBC_MIPS_USE_CB),y)
+KLIBCARCHREQFLAGS += $(call cc-option,-mcompact-branches=never)
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x12FE00000
+else
+KLIBCARCHREQFLAGS += -mcompact-branches=optimal
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x127E00000
+endif
+
+# Kernel uses vDSO for signal return since 2.6.34
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/mips64/crt0.S b/usr/klibc/arch/mips64/crt0.S
new file mode 100644
index 0000000..3f1c2a9
--- /dev/null
+++ b/usr/klibc/arch/mips64/crt0.S
@@ -0,0 +1,21 @@
+#
+# arch/mips64/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+#include <machine/asm.h>
+
+NESTED(__start, 0, ra)
+ move a0, sp # Pointer to ELF entry structure
+ move a1, v0 # Kernel-provided atexit() pointer
+ and sp, -16 # Align stack to 16 bytes
+
+ jal __libc_init
+ teq zero, zero # Crash if we return
+
+ END(__start)
diff --git a/usr/klibc/arch/mips64/setjmp.S b/usr/klibc/arch/mips64/setjmp.S
new file mode 100644
index 0000000..5d902e2
--- /dev/null
+++ b/usr/klibc/arch/mips64/setjmp.S
@@ -0,0 +1,50 @@
+#
+# arch/mips64/setjmp.S
+#
+# setjmp/longjmp for the MIPS architecture
+#
+# The jmp_buf is assumed to contain the following, in order:
+# s0..s7
+# gp
+# sp
+# s8
+# ra
+#
+
+#include <machine/asm.h>
+
+LEAF(setjmp)
+ sd s0, 0(a0)
+ sd s1, 8(a0)
+ sd s2, 16(a0)
+ sd s3, 24(a0)
+ sd s4, 32(a0)
+ sd s5, 40(a0)
+ sd s6, 48(a0)
+ sd s7, 56(a0)
+ sd gp, 64(a0)
+ sd sp, 72(a0)
+ sd s8, 80(a0)
+ sd ra, 88(a0)
+ move v0, zero
+ jr ra
+
+ END(setjmp)
+
+LEAF(longjmp)
+ ld s0, 0(a0)
+ ld s1, 8(a0)
+ ld s2, 16(a0)
+ ld s3, 24(a0)
+ ld s4, 32(a0)
+ ld s5, 40(a0)
+ ld s6, 48(a0)
+ ld s7, 56(a0)
+ ld gp, 64(a0)
+ ld sp, 72(a0)
+ ld s8, 80(a0)
+ ld ra, 88(a0)
+ move v0, a1
+ jr ra
+
+ END(longjmp)
diff --git a/usr/klibc/arch/mips64/sysstub.ph b/usr/klibc/arch/mips64/sysstub.ph
new file mode 100644
index 0000000..57af657
--- /dev/null
+++ b/usr/klibc/arch/mips64/sysstub.ph
@@ -0,0 +1,27 @@
+# -*- perl -*-
+#
+# arch/mips64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On MIPS, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "LEAF(${fname})\n";
+ print OUT "\t li\tv0, __NR_${sname}\n";
+ print OUT "\tj\t__syscall_${stype}\n";
+ print OUT "\tEND(${fname})\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/parisc/Kbuild b/usr/klibc/arch/parisc/Kbuild
new file mode 100644
index 0000000..57ca5c2
--- /dev/null
+++ b/usr/klibc/arch/parisc/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for parisc
+#
+
+klib-y := setjmp.o syscall.o vfork.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/parisc/MCONFIG b/usr/klibc/arch/parisc/MCONFIG
new file mode 100644
index 0000000..bc8bd9b
--- /dev/null
+++ b/usr/klibc/arch/parisc/MCONFIG
@@ -0,0 +1,15 @@
+# -*- makefile -*-
+#
+# arch/parisc/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE = 32
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x40001000
+
+# Kernel uses stack trampoline for signal return
+KLIBCEXECSTACK := y
diff --git a/usr/klibc/arch/parisc/crt0.S b/usr/klibc/arch/parisc/crt0.S
new file mode 100644
index 0000000..0922446
--- /dev/null
+++ b/usr/klibc/arch/parisc/crt0.S
@@ -0,0 +1,37 @@
+ .align 4
+
+ .import $global$, data
+ .import __libc_init, code
+
+ .global _start
+ .export _start, ENTRY
+ .type _start,@function
+
+ .proc
+ .callinfo
+
+_start:
+/* extend the stack by 64-bytes */
+ ldo 64(%sp), %sp
+
+/* %r25 = argc
+ * %r24 = argv
+ * envp = argv + (argc + 1)
+ * elfdata = (argv - 4)
+ */
+ ldo -4(%r24), %r26
+
+/* load global data */
+ ldil L%$global$, %dp
+ ldo R%$global$(%dp), %dp
+
+/* parisc abi puts the atexit pointer in %r23, see ELF_PLAT_INIT() */
+ copy %r23, %r25
+
+/* branch to __libc_init */
+ bl __libc_init,%r2
+ nop
+/* break miserably if we ever return */
+ iitlbp %r0,(%sr0,%r0) /* illegal instruction */
+ nop
+ .procend
diff --git a/usr/klibc/arch/parisc/setjmp.S b/usr/klibc/arch/parisc/setjmp.S
new file mode 100644
index 0000000..c8d766c
--- /dev/null
+++ b/usr/klibc/arch/parisc/setjmp.S
@@ -0,0 +1,88 @@
+/*
+ * parisc specific setjmp/longjmp routines
+ *
+ */
+
+ .text
+ .align 4
+ .global setjmp
+ .export setjmp, code
+ .proc
+ .callinfo
+setjmp:
+ stw %r3,0(%r26)
+ stw %r4,8(%r26)
+ stw %r5,12(%r26)
+ stw %r6,16(%r26)
+ stw %r7,20(%r26)
+ stw %r8,24(%r26)
+ stw %r9,28(%r26)
+ stw %r10,32(%r26)
+ stw %r11,36(%r26)
+ stw %r12,40(%r26)
+ stw %r13,44(%r26)
+ stw %r14,48(%r26)
+ stw %r15,52(%r26)
+ stw %r16,56(%r26)
+ stw %r17,60(%r26)
+ stw %r18,64(%r26)
+ stw %r19,68(%r26)
+ stw %r27,72(%r26)
+ stw %r30,76(%r26)
+ stw %rp,80(%r26)
+ ldo 88(%r26),%r19
+ fstd,ma %fr12,8(%r19)
+ fstd,ma %fr13,8(%r19)
+ fstd,ma %fr14,8(%r19)
+ fstd,ma %fr15,8(%r19)
+ fstd,ma %fr16,8(%r19)
+ fstd,ma %fr17,8(%r19)
+ fstd,ma %fr18,8(%r19)
+ fstd,ma %fr19,8(%r19)
+ fstd,ma %fr20,8(%r19)
+ fstd %fr21,0(%r19)
+ bv %r0(%rp)
+ copy %r0,%r28
+ .procend
+
+ .text
+ .align 4
+ .global longjmp
+ .export longjmp, code
+ .proc
+ .callinfo
+longjmp:
+ ldw 0(%r26),%r3
+ ldw 8(%r26),%r4
+ ldw 12(%r26),%r5
+ ldw 16(%r26),%r6
+ ldw 20(%r26),%r7
+ ldw 24(%r26),%r8
+ ldw 28(%r26),%r9
+ ldw 32(%r26),%r10
+ ldw 36(%r26),%r11
+ ldw 40(%r26),%r12
+ ldw 44(%r26),%r13
+ ldw 48(%r26),%r14
+ ldw 52(%r26),%r15
+ ldw 56(%r26),%r16
+ ldw 60(%r26),%r17
+ ldw 64(%r26),%r18
+ ldw 68(%r26),%r19
+ ldw 72(%r26),%r27
+ ldw 76(%r26),%r30
+ ldw 80(%r26),%rp
+ ldo 88(%r26),%r20
+ fldd,ma 8(%r20),%fr12
+ fldd,ma 8(%r20),%fr13
+ fldd,ma 8(%r20),%fr14
+ fldd,ma 8(%r20),%fr15
+ fldd,ma 8(%r20),%fr16
+ fldd,ma 8(%r20),%fr17
+ fldd,ma 8(%r20),%fr18
+ fldd,ma 8(%r20),%fr19
+ fldd,ma 8(%r20),%fr20
+ fldd 0(%r20),%fr21
+ bv %r0(%rp)
+ copy %r25,%r28
+ .procend
diff --git a/usr/klibc/arch/parisc/syscall.S b/usr/klibc/arch/parisc/syscall.S
new file mode 100644
index 0000000..0ff2a65
--- /dev/null
+++ b/usr/klibc/arch/parisc/syscall.S
@@ -0,0 +1,36 @@
+/*
+ * arch/parisc/syscall.S
+ *
+ * %r20 contains the system call number, %r2 contains whence we came
+ *
+ */
+
+ .text
+ .align 64 ; cache-width aligned
+ .globl __syscall_common
+ .type __syscall_common,@function
+__syscall_common:
+ ldo 0x40(%sp),%sp
+ stw %rp,-0x54(%sp) ; save return pointer
+
+ ldw -0x74(%sp),%r22 ; %arg4
+ ldw -0x78(%sp),%r21 ; %arg5
+
+ ble 0x100(%sr2, %r0) ; jump to gateway page
+ nop ; can we move a load here?
+
+ ldi -0x1000,%r19 ; %r19 = -4096
+ sub %r0,%ret0,%r22 ; %r22 = -%ret0
+ cmpb,>>=,n %r19,%ret0,1f ; if %ret0 >= -4096UL
+ ldi -1,%ret0 ; nullified on taken forward
+
+ /* store %r22 to errno... */
+ ldil L%errno,%r1
+ ldo R%errno(%r1),%r1
+ stw %r22,0(%r1)
+1:
+ ldw -0x54(%sp),%rp ; restore return pointer
+ bv %r0(%rp) ; jump back
+ ldo -0x40(%sp),%sp
+
+ .size __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/parisc/sysstub.ph b/usr/klibc/arch/parisc/sysstub.ph
new file mode 100644
index 0000000..e2196ac
--- /dev/null
+++ b/usr/klibc/arch/parisc/sysstub.ph
@@ -0,0 +1,28 @@
+# -*- perl -*-
+#
+# arch/parisc/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.text\n";
+ print OUT "\t.align 4\n";
+ print OUT "\t.import __syscall_common, code\n";
+ print OUT "\t.global ${fname}\n";
+ print OUT "\t.export ${fname}, code\n";
+ print OUT "\t.proc\n";
+ print OUT "\.callinfo\n";
+ print OUT "${fname}:\n";
+ print OUT "\tb\t__syscall_common\n";
+ print OUT "\t ldo\t__NR_${sname}(%r0),%r20\n";
+ print OUT "\t.procend\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/parisc/vfork.S b/usr/klibc/arch/parisc/vfork.S
new file mode 100644
index 0000000..3868a8d
--- /dev/null
+++ b/usr/klibc/arch/parisc/vfork.S
@@ -0,0 +1,32 @@
+/*
+ * arch/parisc/vfork.S, "vfork() me harder. ugh." -- kyle
+ *
+ * %rp contains whence we came,
+ * %rp is saved and restored across the syscall, thankfully.
+ *
+ */
+
+ .text
+ .align 64 ; cache-width aligned
+ .globl vfork
+ .type vfork,@function
+vfork:
+ /* pid_t vfork(void) */
+ ldi 113,%r20
+ ble 0x100(%sr2, %r0) ; jump to gateway page
+ nop
+
+ ldi -0x1000,%r19 ; %r19 = -4096
+ sub %r0,%ret0,%r22 ; %r22 = -%ret0
+ cmpb,>>=,n %r19,%ret0,1f ; if %ret0 >= -4096UL
+ ldi -1,%ret0 ; nullified on taken forward
+
+ /* store %r22 to errno... */
+ ldil L%errno,%r1
+ ldo R%errno(%r1),%r1
+ stw %r22,0(%r1)
+1:
+ bv %r0(%rp) ; jump back
+ nop
+
+ .size vfork,.-vfork
diff --git a/usr/klibc/arch/ppc/Kbuild b/usr/klibc/arch/ppc/Kbuild
new file mode 100644
index 0000000..699380f
--- /dev/null
+++ b/usr/klibc/arch/ppc/Kbuild
@@ -0,0 +1,12 @@
+#
+# klibc files for ppc
+#
+
+klib-y := setjmp.o syscall.o
+
+klib-y += ../../libgcc/__divdi3.o ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ppc/MCONFIG b/usr/klibc/arch/ppc/MCONFIG
new file mode 100644
index 0000000..db4806a
--- /dev/null
+++ b/usr/klibc/arch/ppc/MCONFIG
@@ -0,0 +1,29 @@
+# -*- makefile -*-
+#
+# arch/ppc/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+gcc_m32_option := $(call cc-option, -m32, )
+
+KLIBCOPTFLAGS += -Os
+KLIBCLDFLAGS = -m elf32ppclinux
+KLIBCARCHREQFLAGS += $(gcc_m32_option)
+
+KLIBCBITSIZE = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 256-16 MB - normal binaries start at 256 MB, and jumps are limited
+# to +/- 16 MB
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x0f800000
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH = powerpc
+
+# Kernel uses vDSO for signal return since 2.6.12 (compat) or 2.6.15 (native)
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/ppc/crt0.S b/usr/klibc/arch/ppc/crt0.S
new file mode 100644
index 0000000..85b6dca
--- /dev/null
+++ b/usr/klibc/arch/ppc/crt0.S
@@ -0,0 +1,23 @@
+#
+# arch/ppc/crt0.S
+#
+
+ .text
+ .align 4
+ .type _start,@function
+ .globl _start
+_start:
+ stwu 1,-16(1)
+ addi 3,1,16
+ /*
+ * the SVR4abippc.pdf specifies r7 as a pointer to
+ * a termination function point
+ * However, Section 8.4.1 of the LSB API docs say that
+ * The value to be placed into register r7, the termination
+ * function pointer, is not passed to the process.
+ * So we stub it out, instead.
+ */
+ li 4,0
+ bl __libc_init
+
+ .size _start,.-_start
diff --git a/usr/klibc/arch/ppc/setjmp.S b/usr/klibc/arch/ppc/setjmp.S
new file mode 100644
index 0000000..e02b7da
--- /dev/null
+++ b/usr/klibc/arch/ppc/setjmp.S
@@ -0,0 +1,34 @@
+#
+# arch/ppc/setjmp.S
+#
+# Basic setjmp/longjmp implementation
+# This file was derived from the equivalent file in NetBSD
+#
+
+ .text
+ .align 4
+ .type setjmp,@function
+ .globl setjmp
+setjmp:
+ mflr %r11 /* save return address */
+ mfcr %r12 /* save condition register */
+ mr %r10,%r1 /* save stack pointer */
+ mr %r9,%r2 /* save GPR2 (not needed) */
+ stmw %r9,0(%r3) /* save r9..r31 */
+ li %r3,0 /* indicate success */
+ blr /* return */
+
+ .size setjmp,.-setjmp
+
+ .type longjmp,@function
+ .globl longjmp
+longjmp:
+ lmw %r9,0(%r3) /* save r9..r31 */
+ mtlr %r11 /* restore LR */
+ mtcr %r12 /* restore CR */
+ mr %r2,%r9 /* restore GPR2 (not needed) */
+ mr %r1,%r10 /* restore stack */
+ mr %r3,%r4 /* get return value */
+ blr /* return */
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/ppc/syscall.S b/usr/klibc/arch/ppc/syscall.S
new file mode 100644
index 0000000..0a7c37c
--- /dev/null
+++ b/usr/klibc/arch/ppc/syscall.S
@@ -0,0 +1,16 @@
+/*
+ * arch/ppc/syscall.S
+ *
+ * Common error-handling path for system calls.
+ */
+
+ .text
+ .align 2
+ .globl __syscall_error
+ .type __syscall_error,@function
+__syscall_error:
+ lis 9,errno@ha
+ stw 3,errno@l(9)
+ li 3,-1
+ blr
+ .size __syscall_error,.-__syscall_error
diff --git a/usr/klibc/arch/ppc/sysstub.ph b/usr/klibc/arch/ppc/sysstub.ph
new file mode 100644
index 0000000..3b3916c
--- /dev/null
+++ b/usr/klibc/arch/ppc/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/ppc/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tli 0,__NR_${sname}\n";
+ print OUT "\tsc\n";
+ print OUT "\tbnslr\n";
+ print OUT "\tb __syscall_error\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/ppc64/Kbuild b/usr/klibc/arch/ppc64/Kbuild
new file mode 100644
index 0000000..a39e91f
--- /dev/null
+++ b/usr/klibc/arch/ppc64/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for ppc64
+#
+
+klib-y := setjmp.o syscall.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/ppc64/MCONFIG b/usr/klibc/arch/ppc64/MCONFIG
new file mode 100644
index 0000000..4326560
--- /dev/null
+++ b/usr/klibc/arch/ppc64/MCONFIG
@@ -0,0 +1,27 @@
+# -*- makefile -*-
+#
+# arch/ppc64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -m64
+KLIBCARCHREQFLAGS += $(call cc-option, -mcall-aixdesc, )
+KLIBCARCHREQFLAGS += $(call cc-option, -mcmodel=small, )
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 64
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 256-16 MB - normal binaries start at 256 MB, and jumps are limited
+# to +/- 16 MB
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x0f000000
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH = powerpc
+
+# Kernel uses vDSO for signal return since 2.6.12
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/ppc64/crt0.S b/usr/klibc/arch/ppc64/crt0.S
new file mode 100644
index 0000000..ed14534
--- /dev/null
+++ b/usr/klibc/arch/ppc64/crt0.S
@@ -0,0 +1,43 @@
+#
+# arch/ppc64/crt0.S
+#
+# void _start(void)
+# {
+# /* Divine up argc, argv, and envp */
+# environ = envp;
+# exit(main(argc, argv, envp));
+# }
+#
+
+ .text
+ .balign 4
+ .globl _start
+#if _CALL_ELF == 2
+ .type _start,@function
+_start:
+#else
+ .section ".opd","aw"
+ .balign 8
+_start:
+ .quad ._start, .TOC.@tocbase, 0
+ .previous
+ .type ._start,@function
+._start:
+#endif
+
+#if _CALL_ELF == 2
+0: addis 2,12,.TOC.-0b@ha
+ addi 2,2,.TOC.-0b@l
+#endif
+
+ stdu %r1,-32(%r1)
+ addi %r3,%r1,32
+ li %r4,0 /* fini (unused) */
+ b __libc_init
+ nop
+
+#if _CALL_ELF == 2
+ .size _start,.-_start
+#else
+ .size _start,.-._start
+#endif
diff --git a/usr/klibc/arch/ppc64/setjmp.S b/usr/klibc/arch/ppc64/setjmp.S
new file mode 100644
index 0000000..ecf9717
--- /dev/null
+++ b/usr/klibc/arch/ppc64/setjmp.S
@@ -0,0 +1,103 @@
+#
+# arch/ppc64/setjmp.S
+#
+# Basic setjmp/longjmp implementation
+#
+
+ .text
+ .balign 4
+ .globl setjmp
+#if _CALL_ELF == 2
+ .type setjmp,@function
+setjmp:
+#else
+ .section ".opd","aw"
+ .balign 8
+setjmp:
+ .quad .setjmp, .TOC.@tocbase, 0
+ .previous
+ .type .setjmp,@function
+ .globl .setjmp
+.setjmp:
+#endif
+ mflr %r11 /* save return address */
+ mfcr %r12 /* save condition register */
+ std %r2,0(%r3) /* save TOC pointer (not needed) */
+ stdu %r1,8(%r3) /* save stack pointer */
+ stdu %r11,8(%r3)
+ stdu %r12,8(%r3)
+ stdu %r13,8(%r3) /* save caller saved regs */
+ stdu %r14,8(%r3)
+ stdu %r15,8(%r3)
+ stdu %r16,8(%r3)
+ stdu %r17,8(%r3)
+ stdu %r18,8(%r3)
+ stdu %r19,8(%r3)
+ stdu %r20,8(%r3)
+ stdu %r21,8(%r3)
+ stdu %r22,8(%r3)
+ stdu %r23,8(%r3)
+ stdu %r24,8(%r3)
+ stdu %r25,8(%r3)
+ stdu %r26,8(%r3)
+ stdu %r27,8(%r3)
+ stdu %r28,8(%r3)
+ stdu %r29,8(%r3)
+ stdu %r30,8(%r3)
+ std %r31,8(%r3)
+ li %r3,0 /* indicate success */
+ blr /* return */
+#if _CALL_ELF == 2
+ .size setjmp,.-setjmp
+#else
+ .size setjmp,.-.setjmp
+#endif
+
+ .text
+ .balign 4
+ .globl longjmp
+#if _CALL_ELF == 2
+ .type longjmp,@function
+longjmp:
+#else
+ .section ".opd","aw"
+ .balign 8
+longjmp:
+ .quad .longjmp, .TOC.@tocbase, 0
+ .previous
+ .type .longjmp,@function
+ .globl .longjmp
+.longjmp:
+#endif
+ ld %r2,0(%r3) /* restore TOC pointer (not needed) */
+ ldu %r1,8(%r3) /* restore stack */
+ ldu %r11,8(%r3)
+ ldu %r12,8(%r3)
+ ldu %r13,8(%r3) /* restore caller saved regs */
+ ldu %r14,8(%r3)
+ ldu %r15,8(%r3)
+ ldu %r16,8(%r3)
+ ldu %r17,8(%r3)
+ ldu %r18,8(%r3)
+ ldu %r19,8(%r3)
+ ldu %r20,8(%r3)
+ ldu %r21,8(%r3)
+ ldu %r22,8(%r3)
+ ldu %r23,8(%r3)
+ ldu %r24,8(%r3)
+ ldu %r25,8(%r3)
+ ldu %r26,8(%r3)
+ ldu %r27,8(%r3)
+ ldu %r28,8(%r3)
+ ldu %r29,8(%r3)
+ ldu %r30,8(%r3)
+ ld %r31,8(%r3)
+ mtlr %r11 /* restore LR */
+ mtcr %r12 /* restore CR */
+ mr %r3,%r4 /* get return value */
+ blr /* return */
+#if _CALL_ELF == 2
+ .size longjmp,.-longjmp
+#else
+ .size longjmp,.-.longjmp
+#endif
diff --git a/usr/klibc/arch/ppc64/syscall.c b/usr/klibc/arch/ppc64/syscall.c
new file mode 100644
index 0000000..a5895fe
--- /dev/null
+++ b/usr/klibc/arch/ppc64/syscall.c
@@ -0,0 +1,14 @@
+/*
+ * arch/ppc64/syscall.c
+ *
+ * Common error-handling path for system calls.
+ * The return value from __syscall_error becomes the
+ * return value from the system call.
+ */
+#include <errno.h>
+
+long int __syscall_error(long int err)
+{
+ errno = err;
+ return -1;
+}
diff --git a/usr/klibc/arch/ppc64/sysstub.ph b/usr/klibc/arch/ppc64/sysstub.ph
new file mode 100644
index 0000000..a0c6d41
--- /dev/null
+++ b/usr/klibc/arch/ppc64/sysstub.ph
@@ -0,0 +1,47 @@
+# -*- perl -*-
+#
+# arch/ppc64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT <<EOF;
+#include <asm/unistd.h>
+
+ .text
+ .balign 4
+ .globl ${fname}
+#if _CALL_ELF == 2
+ .type ${fname},\@function
+${fname}:
+0: addis 2,12,(.TOC.-0b)\@ha
+ addi 2,2,(.TOC.-0b)\@l
+ .localentry ${fname},.-${fname}
+#else
+ .section ".opd","aw"
+ .balign 8
+${fname}:
+ .quad .${fname}, .TOC.\@tocbase, 0
+ .previous
+ .type .${fname},\@function
+ .globl .${fname}
+.${fname}:
+#endif
+ li 0, __NR_${sname}
+ sc
+ bnslr
+ b __syscall_error
+#if _CALL_ELF == 2
+ .size ${fname},.-${fname}
+#else
+ .size ${fname},.-.${fname}
+#endif
+EOF
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/riscv64/Kbuild b/usr/klibc/arch/riscv64/Kbuild
new file mode 100644
index 0000000..218f386
--- /dev/null
+++ b/usr/klibc/arch/riscv64/Kbuild
@@ -0,0 +1,12 @@
+# -*- makefile -*-
+#
+# klibc files for riscv64
+
+always := crt0.o _main.o
+targets := crt0.o _main.o
+
+klib-y := setjmp.o syscall.o
+
+install-rule:
+ $(Q)$(shell $(install-data) $(call objectify,_main.o) \
+ $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib)
diff --git a/usr/klibc/arch/riscv64/MCONFIG b/usr/klibc/arch/riscv64/MCONFIG
new file mode 100644
index 0000000..717aeda
--- /dev/null
+++ b/usr/klibc/arch/riscv64/MCONFIG
@@ -0,0 +1,29 @@
+# -*- makefile -*-
+#
+# arch/riscv64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+ifeq ($(DEBUG),y)
+KLIBCOPTFLAGS += -g
+endif
+KLIBCBITSIZE = 64
+
+# Normal binaries start at 64 kiB. Jumps can use either a single
+# instruction with offset of ±1 MiB, or two instructions with offset
+# of ±2 GiB. Putting klibc.so close above the executable can cause
+# breakage, so instead swap them around: klibc.so at 64 kiB and
+# executable at 576 kiB.
+KLIBCLDFLAGS = $(LD_IMAGE_BASE_OPT) 0x90000
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x10000
+KLIBCSHAREDFLAGS += --defsym '__global_pointer$$=0'
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
+
+KLIBCEMAIN := -e _main
+KLIBCCRTSHARED += $(KLIBCOBJ)/arch/riscv64/_main.o
diff --git a/usr/klibc/arch/riscv64/_main.S b/usr/klibc/arch/riscv64/_main.S
new file mode 100644
index 0000000..284a222
--- /dev/null
+++ b/usr/klibc/arch/riscv64/_main.S
@@ -0,0 +1,17 @@
+#
+# arch/riscv64/_main.S
+#
+# Does arch-specific initialization and invokes main with the
+# appropriate arguments.
+#
+
+#include <machine/asm.h>
+
+ENTRY(_main)
+ .option push
+ .option norelax
+ lla gp, __global_pointer$
+ .option pop
+
+ j main
+END(_main)
diff --git a/usr/klibc/arch/riscv64/crt0.S b/usr/klibc/arch/riscv64/crt0.S
new file mode 100644
index 0000000..76fa3c2
--- /dev/null
+++ b/usr/klibc/arch/riscv64/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/riscv64/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+#include <machine/asm.h>
+
+ENTRY(_start)
+ .option push
+ .option norelax
+ lla gp, __global_pointer$
+ .option pop
+
+ mv a0, sp # Pointer to ELF entry structure
+ mv a1, zero # No onexit pointer
+ jal __libc_init
+END(_start)
diff --git a/usr/klibc/arch/riscv64/setjmp.S b/usr/klibc/arch/riscv64/setjmp.S
new file mode 100644
index 0000000..66e009e
--- /dev/null
+++ b/usr/klibc/arch/riscv64/setjmp.S
@@ -0,0 +1,50 @@
+/*
+ * arch/riscv64/setjmp.S
+ *
+ * setjmp/longjmp for the RISC-V (RV64) architecture
+ *
+ * The jmp_buf is assumed to contain the following, in order:
+ * pc (ra)
+ * s0..s11
+ * sp
+ */
+
+#include <machine/asm.h>
+
+ENTRY(setjmp)
+ sd ra, 0(a0)
+ sd s0, 8(a0)
+ sd s1, 16(a0)
+ sd s2, 24(a0)
+ sd s3, 32(a0)
+ sd s4, 40(a0)
+ sd s5, 48(a0)
+ sd s6, 56(a0)
+ sd s7, 64(a0)
+ sd s8, 72(a0)
+ sd s9, 80(a0)
+ sd s10, 88(a0)
+ sd s11, 96(a0)
+ sd sp, 104(a0)
+ mv a0, zero
+ jr ra
+END(setjmp)
+
+ENTRY(longjmp)
+ ld ra, 0(a0)
+ ld s0, 8(a0)
+ ld s1, 16(a0)
+ ld s2, 24(a0)
+ ld s3, 32(a0)
+ ld s4, 40(a0)
+ ld s5, 48(a0)
+ ld s6, 56(a0)
+ ld s7, 64(a0)
+ ld s8, 72(a0)
+ ld s9, 80(a0)
+ ld s10, 88(a0)
+ ld s11, 96(a0)
+ ld sp, 104(a0)
+ mv a0, a1
+ jr ra
+END(longjmp)
diff --git a/usr/klibc/arch/riscv64/syscall.S b/usr/klibc/arch/riscv64/syscall.S
new file mode 100644
index 0000000..89d9bd2
--- /dev/null
+++ b/usr/klibc/arch/riscv64/syscall.S
@@ -0,0 +1,13 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ENTRY(__syscall_common)
+ scall
+ li t0, -4096
+ bleu a0, t0, 1f
+ neg a0, a0
+ lui t0, %hi(errno)
+ sw a0, %lo(errno)(t0)
+ li a0, -1
+1: jr ra
+END(__syscall_common)
diff --git a/usr/klibc/arch/riscv64/sysstub.ph b/usr/klibc/arch/riscv64/sysstub.ph
new file mode 100644
index 0000000..85c1beb
--- /dev/null
+++ b/usr/klibc/arch/riscv64/sysstub.ph
@@ -0,0 +1,26 @@
+# -*- perl -*-
+#
+# arch/riscv/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On RISC-V, most system calls follow the standard convention, with the
+# system call number in x17 (a7) and the return value in x10 (a0).
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "ENTRY(${fname})\n";
+ print OUT "\tli\ta7, __NR_${sname}\n";
+ print OUT "\tj\t__syscall_${stype}\n";
+ print OUT "END(${fname})\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/s390/Kbuild b/usr/klibc/arch/s390/Kbuild
new file mode 100644
index 0000000..6a8e97a
--- /dev/null
+++ b/usr/klibc/arch/s390/Kbuild
@@ -0,0 +1,22 @@
+#
+# klibc files for s390
+#
+
+always := crt0.o
+targets := crt0.o
+
+ifneq ("$(KLIBCARCH)", "s390x")
+
+klib-y := setjmp.o mmap.o syscall.o
+
+klib-y += ../../libgcc/__clzsi2.o ../../libgcc/__ashldi3.o
+klib-y += ../../libgcc/__ashrdi3.o ../../libgcc/__lshrdi3.o
+klib-y += ../../libgcc/__divdi3.o ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+else
+
+klib-y := setjmp.o mmap.o syscall.o
+
+endif
diff --git a/usr/klibc/arch/s390/MCONFIG b/usr/klibc/arch/s390/MCONFIG
new file mode 100644
index 0000000..a704c5a
--- /dev/null
+++ b/usr/klibc/arch/s390/MCONFIG
@@ -0,0 +1,26 @@
+# -*- makefile -*-
+#
+# arch/s390/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os
+
+ifneq ("$(KLIBCARCH)", "s390x")
+ KLIBCBITSIZE = 32
+ KLIBCCFLAGS += -m31
+ KLIBCLDFLAGS += -m elf_s390
+else
+ KLIBCBITSIZE = 64
+ KLIBCCFLAGS += -m64
+ KLIBCLDFLAGS += -m elf64_s390
+endif
+
+KLIBCASMARCH = s390
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x40000000
+
+# Kernel uses our sa_restorer for signal return
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/s390/crt0.S b/usr/klibc/arch/s390/crt0.S
new file mode 100644
index 0000000..fd9237e
--- /dev/null
+++ b/usr/klibc/arch/s390/crt0.S
@@ -0,0 +1,35 @@
+#
+# arch/s390/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+ .text
+ .align 4
+ .type _start,@function
+ .globl _start
+
+#ifndef __s390x__
+
+_start:
+ lr %r2,%r15
+ lhi %r3,0
+ ahi %r15,-96
+ bras %r1,.L0
+.L0:
+ l %r1,.L1-.L0(%r1)
+ br %r1
+.L1:
+ .long __libc_init
+#else
+
+_start:
+ lgr %r2,%r15
+ lghi %r3,0
+ aghi %r15,-160
+ jg __libc_init
+#endif
+ .size _start,.-_start
diff --git a/usr/klibc/arch/s390/mmap.c b/usr/klibc/arch/s390/mmap.c
new file mode 100644
index 0000000..dfc5a84
--- /dev/null
+++ b/usr/klibc/arch/s390/mmap.c
@@ -0,0 +1,74 @@
+#include <errno.h>
+#include <sys/types.h>
+#include <linux/unistd.h>
+
+struct mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+#ifndef __s390x__
+
+void *__mmap2(void *addr, size_t len, int prot, int flags, int fd, long offset)
+{
+ struct mmap_arg_struct args = {
+ .addr = (unsigned long)addr,
+ .len = (unsigned long)len,
+ .prot = (unsigned long)prot,
+ .flags = (unsigned long)flags,
+ .fd = (unsigned long)fd,
+ .offset = (unsigned long)offset,
+ };
+
+ register struct mmap_arg_struct *__arg1 asm("2") = &args;
+ register long __svcres asm("2");
+ unsigned long __res;
+
+ __asm__ __volatile__(" svc %b1\n"
+ : "=d"(__svcres)
+ : "i"(__NR_mmap2), "0"(__arg1)
+ : "1", "cc", "memory");
+ __res = __svcres;
+ if (__res >= (unsigned long)-4095) {
+ errno = -__res;
+ __res = -1;
+ }
+ return (void *)__res;
+}
+
+#else /* __s390x__ */
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+ struct mmap_arg_struct args = {
+ .addr = (unsigned long)addr,
+ .len = (unsigned long)len,
+ .prot = (unsigned long)prot,
+ .flags = (unsigned long)flags,
+ .fd = (unsigned long)fd,
+ .offset = (unsigned long)offset,
+ };
+
+ register struct mmap_arg_struct *__arg1 asm("2") = &args;
+ register long __svcres asm("2");
+ unsigned long __res;
+
+ __asm__ __volatile__ (
+ " svc %1\n"
+ : "=d" (__svcres)
+ : "i" (__NR_mmap),
+ "0" (__arg1)
+ : "1", "cc", "memory");
+ __res = __svcres;
+ if (__res >= (unsigned long)-4095) {
+ errno = -__res;
+ __res = -1;
+ }
+ return (void *)__res;
+}
+
+#endif /* __s390x__ */
diff --git a/usr/klibc/arch/s390/setjmp.S b/usr/klibc/arch/s390/setjmp.S
new file mode 100644
index 0000000..1386419
--- /dev/null
+++ b/usr/klibc/arch/s390/setjmp.S
@@ -0,0 +1,74 @@
+#
+# arch/s390/setjmp.S
+#
+# setjmp/longjmp for the s390 architecture
+#
+
+ .text
+ .align 4
+ .globl setjmp
+ .type setjmp, @function
+
+#ifndef __s390x__
+
+setjmp:
+ stm %r6,%r15,0(%r2) # save all general registers
+ std %f4,40(%r2) # save fp registers f4 and f6
+ std %f6,48(%r2)
+ lhi %r2,0 # return 0
+ br %r14
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ lr %r1,%r2 # jmp_buf
+ lr %r2,%r3 # return value
+ ld %f6,48(%r1) # restore all saved registers
+ ld %f4,40(%r1)
+ lm %r6,%r15,0(%r1)
+ br %r14 # return to restored address
+
+ .size longjmp,.-longjmp
+
+#else
+
+setjmp:
+ stmg %r6,%r15,0(%r2) # save all general registers
+ std %f8,80(%r2) # save fp registers f8 to f15
+ std %f9,88(%r2)
+ std %f10,96(%r2)
+ std %f11,104(%r2)
+ std %f12,112(%r2)
+ std %f13,120(%r2)
+ std %f14,128(%r2)
+ std %f15,136(%r2)
+ lghi %r2,0 # return 0
+ br %r14
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ lgr %r1,%r2 # jmp_buf
+ lgr %r2,%r3 # return value
+ ld %f15,136(%r1) # restore all saved registers
+ ld %f14,128(%r1)
+ ld %f13,120(%r1)
+ ld %f12,112(%r1)
+ ld %f11,104(%r1)
+ ld %f10,96(%r1)
+ ld %f9,88(%r1)
+ ld %f8,80(%r1)
+ lmg %r6,%r15,0(%r1)
+ br %r14 # return to restored address
+
+ .size longjmp,.-longjmp
+
+#endif
diff --git a/usr/klibc/arch/s390/syscall.c b/usr/klibc/arch/s390/syscall.c
new file mode 100644
index 0000000..e1d201d
--- /dev/null
+++ b/usr/klibc/arch/s390/syscall.c
@@ -0,0 +1,16 @@
+/*
+ * arch/s390/syscall.c
+ *
+ * Common error-handling path for system calls.
+ * The return value from __syscall_common becomes the
+ * return value from the system call.
+ */
+#include <errno.h>
+
+unsigned long __syscall_common(unsigned long err)
+{
+ if (err < -4095UL)
+ return err;
+ errno = -err;
+ return -1;
+}
diff --git a/usr/klibc/arch/s390/sysstub.ph b/usr/klibc/arch/s390/sysstub.ph
new file mode 100644
index 0000000..1ca7b6b
--- /dev/null
+++ b/usr/klibc/arch/s390/sysstub.ph
@@ -0,0 +1,63 @@
+# -*- perl -*-
+#
+# arch/s390/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+ my($t);
+ my($r, $llregs) = (0, ($typesize{'void *'} == 8) ? 1 : 2);
+
+ foreach $t (@args) {
+ $r += ($typesize{$t} == 8) ? $llregs : 1;
+ }
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT <<EOF;
+#include <asm/unistd.h>
+
+ .type ${fname},\@function
+ .globl ${fname}
+${fname}:
+.if ${r} > 6
+.print "System call with more than six parameters not supported yet."
+.err
+.endif
+.if ${r} == 6
+#ifndef __s390x__
+ st %r7,56(%r15)
+ l %r7,96(%r15)
+#else
+ stg %r7,80(%r15)
+ lg %r7,160(%r15)
+#endif
+.endif
+.if __NR_${sname} < 256
+ svc __NR_${sname}
+.else
+ la %r1,__NR_${sname}
+ svc 0
+.endif
+.if ${r} == 6
+#ifndef __s390x__
+ l %r7,56(%r15)
+#else
+ lg %r7,160(%r15)
+#endif
+.endif
+#ifndef __s390x__
+ bras %r3,1f
+ .long __syscall_common
+1: l %r3,0(%r3)
+ br %r3
+#else
+ brasl %r3,__syscall_common
+#endif
+ .size ${fname},.-${fname}
+EOF
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sh/Kbuild b/usr/klibc/arch/sh/Kbuild
new file mode 100644
index 0000000..29b606a
--- /dev/null
+++ b/usr/klibc/arch/sh/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for sh
+#
+
+klib-y := pipe.o setjmp.o syscall.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/sh/MCONFIG b/usr/klibc/arch/sh/MCONFIG
new file mode 100644
index 0000000..43d608c
--- /dev/null
+++ b/usr/klibc/arch/sh/MCONFIG
@@ -0,0 +1,20 @@
+# -*- makefile -*-
+#
+# arch/sh/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer
+KLIBCBITSIZE = 32
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2 MB -- the normal starting point for text is 4 MB.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x00200000
+
+# Kernel uses vDSO for signal return since 2.6.19
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/sh/crt0.S b/usr/klibc/arch/sh/crt0.S
new file mode 100644
index 0000000..7f0a649
--- /dev/null
+++ b/usr/klibc/arch/sh/crt0.S
@@ -0,0 +1,27 @@
+#
+# arch/sh/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+ .text
+ .align 2
+ .type _start,#function
+ .globl _start
+
+_start:
+ mov r15, r4
+ mov #0, r5
+ mov.l 1f, r0
+
+ jsr @r0
+ nop
+
+ .align 2
+1: .long __libc_init
+
+ .size _start,.-_start
diff --git a/usr/klibc/arch/sh/pipe.S b/usr/klibc/arch/sh/pipe.S
new file mode 100644
index 0000000..01b055b
--- /dev/null
+++ b/usr/klibc/arch/sh/pipe.S
@@ -0,0 +1,35 @@
+/*
+ * arch/sh/pipe.S
+ *
+ * The pipe system call is special on sh: it returns
+ * the two file descriptors in r0 and r1.
+ */
+
+#include <asm/unistd.h>
+
+ .section ".text.syscall","ax"
+ .align 2
+ .globl pipe
+ .type pipe,@function
+pipe:
+ mov #__NR_pipe, r3
+ trapa #0x10
+ mov.l 1f,r2
+ cmp/hs r0,r2
+ bt/s 3f
+ neg r0,r2
+ mov.l 2f,r3
+ mov.l r2,@r3
+ rts
+ mov #-1,r0
+3:
+ mov.l r0, @r4
+ mov.l r1, @(4, r4)
+ rts
+ mov #0,r0
+
+ .align 2
+1: .long -4096 /* Errno limit */
+2: .long errno
+
+ .size pipe,.-pipe
diff --git a/usr/klibc/arch/sh/setjmp.S b/usr/klibc/arch/sh/setjmp.S
new file mode 100644
index 0000000..2552358
--- /dev/null
+++ b/usr/klibc/arch/sh/setjmp.S
@@ -0,0 +1,64 @@
+#
+# arch/sh/setjmp.S
+#
+# setjmp/longjmp for the SuperH architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#
+# r8
+# r9
+# r10
+# r11
+# r12
+# r13
+# r14
+# r15
+# pr
+#
+
+ .text
+ .align 2
+
+ .globl setjmp
+ .type setjmp, #function
+
+setjmp:
+ add #(9*4), r4
+ sts.l pr, @-r4
+ mov.l r15, @-r4
+ mov.l r14, @-r4
+ mov.l r13, @-r4
+ mov.l r12, @-r4
+ mov.l r11, @-r4
+ mov.l r10, @-r4
+ mov.l r9, @-r4
+ mov.l r8, @-r4
+ rts
+ mov #0, r0
+
+ .size setjmp,.-setjmp
+
+ .align 2
+ .globl longjmp
+ .type setjmp, #function
+
+longjmp:
+ mov.l @r4+, r8
+ mov.l @r4+, r9
+ mov.l @r4+, r10
+ mov.l @r4+, r11
+ mov.l @r4+, r12
+ mov.l @r4+, r13
+ mov.l @r4+, r14
+ mov.l @r4+, r15
+ lds.l @r4+, pr
+ mov r5, r0
+ tst r0, r0
+ bf 1f
+ mov #1, r0 ! in case val==0
+1: rts
+ nop
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/sh/syscall.S b/usr/klibc/arch/sh/syscall.S
new file mode 100644
index 0000000..77245b7
--- /dev/null
+++ b/usr/klibc/arch/sh/syscall.S
@@ -0,0 +1,35 @@
+/*
+ * arch/sh/syscall.S
+ *
+ * On sh, r3 contains the syscall number (set by generated stub);
+ * r4..r7 contain arguments 0-3 per the standard calling convention,
+ * and arguments 4-5 are passed in r0 and r1.
+ *
+ * The return value is in r0.
+ */
+
+ .section ".text.syscall","ax"
+ .align 2
+ .globl __syscall_common
+ .type __syscall_common,@function
+__syscall_common:
+ mov.l @(0,sp),r0
+ mov.l @(4,sp),r1
+ trapa #0x15
+ mov.l 1f,r1
+ cmp/hs r0,r1
+ bt/s 3f
+ neg r0,r1
+ mov.l 2f,r2
+ mov.l r1,@r2
+ rts
+ mov #-1,r0
+3:
+ rts
+ nop
+
+ .align 2
+1: .long -4096 /* Errno limit */
+2: .long errno
+
+ .size __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/sh/sysstub.ph b/usr/klibc/arch/sh/sysstub.ph
new file mode 100644
index 0000000..0ff46dd
--- /dev/null
+++ b/usr/klibc/arch/sh/sysstub.ph
@@ -0,0 +1,38 @@
+# -*- perl -*-
+#
+# arch/sh/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.section\t\".text.syscall\",\"ax\"\n";
+ print OUT "\t.type\t${fname},\#function\n";
+ print OUT "\t.globl\t${fname}\n";
+ print OUT "\t.align\t2\n";
+ print OUT "\t.import __syscall_common\n";
+ print OUT "${fname}:\n";
+ print OUT "\t mov.l\t1f, r3\n";
+ print OUT "\t jmp\t\@r3\n";
+ print OUT "#if __NR_${sname} >= 128\n";
+ print OUT "\t mov.l\t2f, r3\n";
+ print OUT "#else\n";
+ print OUT "\t mov\t# __NR_${sname}, r3\n";
+ print OUT "#endif\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ print OUT "\n";
+ print OUT "\t.align\t2\n";
+ print OUT "\t.import\t__syscall_common\n";
+ print OUT "1:\t.long\t__syscall_common\n";
+ print OUT "#if __NR_${sname} >= 128\n";
+ print OUT "2:\t.long\t__NR_${sname}\n";
+ print OUT "#endif\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sparc/Kbuild b/usr/klibc/arch/sparc/Kbuild
new file mode 100644
index 0000000..d92bbb0
--- /dev/null
+++ b/usr/klibc/arch/sparc/Kbuild
@@ -0,0 +1,34 @@
+#
+# klibc files for sparc
+#
+
+always := crt0.o
+targets := crt0.o
+
+m4-targets := sdiv.o srem.o udiv.o urem.o
+
+klib-y := $(m4-targets) smul.o umul.o __muldi3.o
+klib-y += setjmp.o pipe.o sigaction.o syscall.o sysfork.o
+
+klib-y += ../../libgcc/__ashldi3.o ../../libgcc/__ashrdi3.o
+klib-y += ../../libgcc/__lshrdi3.o ../../libgcc/__divdi3.o
+klib-y += ../../libgcc/__moddi3.o ../../libgcc/__udivdi3.o
+klib-y += ../../libgcc/__umoddi3.o ../../libgcc/__udivmoddi4.o
+klib-y += ../../libgcc/__clzsi2.o
+
+
+$(obj)/sdiv.S: m4 := define(NAME,\`.div')define(OP,\`div')define(S,\`true')
+$(obj)/srem.S: m4 := define(NAME,\`.rem')define(OP,\`rem')define(S,\`true')
+$(obj)/udiv.S: m4 := define(NAME,\`.udiv')define(OP,\`div')define(S,\`false')
+$(obj)/urem.S: m4 := define(NAME,\`.urem')define(OP,\`rem')define(S,\`false')
+
+targets += $(m4-targets) $(m4-targets:.o=.S)
+
+quiet_cmd_m4 = M4 $@
+ cmd_m4 = (echo "$(m4)"; cat $^) | m4 > $@
+
+# build .o from .S
+$(addprefix $(obj)/,$(m4-targets)): $(obj)/%.o : $(obj)/%.S
+# build .S from .m4
+$(addprefix $(obj)/,$(m4-targets:.o=.S)): $(src)/divrem.m4
+ $(call if_changed,m4)
diff --git a/usr/klibc/arch/sparc/MCONFIG b/usr/klibc/arch/sparc/MCONFIG
new file mode 100644
index 0000000..623223d
--- /dev/null
+++ b/usr/klibc/arch/sparc/MCONFIG
@@ -0,0 +1,22 @@
+# -*- makefile -*-
+#
+# arch/sparc/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCOPTFLAGS += -Os -m32 -mptr32
+KLIBCBITSIZE = 32
+KLIBCARCHREQFLAGS += -D__sparc32__
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# Normal binaries start at 64K; the linker wants 64K alignment,
+# and call instructions have a 30-bit signed offset, << 2.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x40000000
+
+# Kernel uses our sa_restorer for signal return
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/sparc/__muldi3.S b/usr/klibc/arch/sparc/__muldi3.S
new file mode 100644
index 0000000..e53848a
--- /dev/null
+++ b/usr/klibc/arch/sparc/__muldi3.S
@@ -0,0 +1,27 @@
+ .global .umul
+ .section ".text"
+ .align 4
+ .global __muldi3
+ .type __muldi3, #function
+ .proc 017
+__muldi3:
+ save %sp, -104, %sp
+ mov %i1, %o0
+ call .umul, 0
+ mov %i3, %o1
+ mov %o0, %l2
+ mov %o1, %l3
+ mov %i1, %o0
+ call .umul, 0
+ mov %i2, %o1
+ mov %i0, %o1
+ mov %o0, %l0
+ call .umul, 0
+ mov %i3, %o0
+ mov 0, %l1
+ add %l0, %o0, %l0
+ addcc %l3, %l1, %i1
+ addx %l2, %l0, %i0
+ jmp %i7+8
+ restore
+ .size __muldi3, .-__muldi3
diff --git a/usr/klibc/arch/sparc/crt0.S b/usr/klibc/arch/sparc/crt0.S
new file mode 100644
index 0000000..63db188
--- /dev/null
+++ b/usr/klibc/arch/sparc/crt0.S
@@ -0,0 +1,2 @@
+#define TARGET_PTR_SIZE 32
+#include "crt0i.S"
diff --git a/usr/klibc/arch/sparc/crt0i.S b/usr/klibc/arch/sparc/crt0i.S
new file mode 100644
index 0000000..0220b01
--- /dev/null
+++ b/usr/klibc/arch/sparc/crt0i.S
@@ -0,0 +1,100 @@
+! This file derived from the equivalent in newlib
+!
+! C run time start off
+
+! This file supports:
+!
+! - both 32bit pointer and 64bit pointer environments (at compile time)
+! - an imposed stack bias (of 2047) (at run time)
+! - medium/low and medium/anywhere code models (at run time)
+
+! Initial stack setup:
+!
+! bottom of stack (higher memory address)
+! ...
+! text of environment strings
+! text of argument strings
+! envp[envc] = 0 (4/8 bytes)
+! ...
+! env[0] (4/8 bytes)
+! argv[argc] = 0 (4/8 bytes)
+! ...
+! argv[0] (4/8 bytes)
+! argc (4/8 bytes)
+! register save area (64 bits by 16 registers = 128 bytes)
+! top of stack (%sp)
+
+! Stack Bias:
+!
+! It is the responsibility of the o/s to set this up.
+! We handle both a 0 and 2047 value for the stack bias.
+
+! Medium/Anywhere code model support:
+!
+! In this model %g4 points to the start of the data segment.
+! The text segment can go anywhere, but %g4 points to the *data* segment.
+! It is up to the compiler/linker to get this right.
+!
+! Since this model is statically linked the start of the data segment
+! is known at link time. Eg:
+!
+! sethi %hh(data_start), %g1
+! sethi %lm(data_start), %g4
+! or %g1, %hm(data_start), %g1
+! or %g4, %lo(data_start), %g4
+! sllx %g1, 32, %g1
+! or %g4, %g1, %g4
+!
+! FIXME: For now we just assume 0.
+
+! FIXME: if %g1 contains a non-zero value, atexit() should be invoked
+! with this value.
+
+
+ .text
+ .align 4
+ .globl _start
+ .type _start, @function
+_start:
+ clr %fp
+
+! We use %g4 even if the code model is Medium/Low (simplifies the code).
+
+ clr %g4 ! Medium/Anywhere base reg
+
+! If there is a stack bias in effect, account for it in %g5. Then always
+! add %g5 to stack references below. This way the code can be used with
+! or without an imposed bias.
+
+ andcc %sp, 1, %g5
+ bz,a .LNoBias
+ nop
+ mov 2047, %g5
+.LNoBias:
+ add %sp, %g5, %g5
+
+! On entry, the kernel leaves room for one register frame, but
+! the C API wants more free space. Thus, we need to drop the stack
+! pointer additionally.
+
+#if TARGET_PTR_SIZE == 32
+ sub %sp, 32, %sp ! make room for incoming arguments
+#else /* TARGET_PTR_SIZE == 64 */
+ sub %sp, 64, %sp ! make room for incoming arguments
+#endif
+
+! Set up pointers to the ELF data structure (argc, argv, ...)
+! Pass as the first argument to __libc_init
+#if TARGET_PTR_SIZE == 32
+ add %g5, 0x40, %o0
+#else /* TARGET_PTR_SIZE == 64 */
+ add %g5, 0x80, %o0
+#endif
+
+ call __libc_init
+ mov %g1, %o1 ! This is the "atexit" pointer;
+ ! pass as the second argument to __libc_init
+
+! If __libc_init returns, something is hosed. Try an illegal insn.
+! If that does not work, the o/s is hosed more than we are.
+ .long 0
diff --git a/usr/klibc/arch/sparc/divrem.m4 b/usr/klibc/arch/sparc/divrem.m4
new file mode 100644
index 0000000..aa4171d
--- /dev/null
+++ b/usr/klibc/arch/sparc/divrem.m4
@@ -0,0 +1,276 @@
+/*
+ * 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: divrem.m4,v 1.4 92/06/25 13:23:57 torek Exp
+ * $NetBSD: divrem.m4,v 1.4 1997/10/09 10:07:54 lukem Exp $
+ */
+
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+ .asciz "@(#)divrem.m4 8.1 (Berkeley) 6/4/93"
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * NAME name of function to generate
+ * OP OP=div => %o0 / %o1; OP=rem => %o0 % %o1
+ * S S=true => signed; S=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TWOSUPN 2^N, for label generation (m4 exponentiation currently broken)
+ * TOPBITS number of bits in the top `decade' of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+define(N, `4')
+define(TWOSUPN, `16')
+define(WORDSIZE, `32')
+define(TOPBITS, eval(WORDSIZE - N*((WORDSIZE-1)/N)))
+
+define(dividend, `%o0')
+define(divisor, `%o1')
+define(Q, `%o2')
+define(R, `%o3')
+define(ITER, `%o4')
+define(V, `%o5')
+
+/* m4 reminder: ifelse(a,b,c,d) => if a is b, then c, else d */
+define(T, `%g1')
+define(SC, `%g7')
+ifelse(S, `true', `define(SIGN, `%g6')')
+
+/*
+ * This is the recursive definition for developing quotient digits.
+ *
+ * Parameters:
+ * $1 the current depth, 1 <= $1 <= N
+ * $2 the current accumulation of quotient bits
+ * N max depth
+ *
+ * We add a new bit to $2 and either recurse or insert the bits in
+ * the quotient. R, Q, and V are inputs and outputs as defined above;
+ * the condition codes are expected to reflect the input R, and are
+ * modified to reflect the output R.
+ */
+define(DEVELOP_QUOTIENT_BITS,
+` ! depth $1, accumulated bits $2
+ bl L.$1.eval(TWOSUPN+$2)
+ srl V,1,V
+ ! remainder is positive
+ subcc R,V,R
+ ifelse($1, N,
+ ` b 9f
+ add Q, ($2*2+1), Q
+ ', ` DEVELOP_QUOTIENT_BITS(incr($1), `eval(2*$2+1)')')
+L.$1.eval(TWOSUPN+$2):
+ ! remainder is negative
+ addcc R,V,R
+ ifelse($1, N,
+ ` b 9f
+ add Q, ($2*2-1), Q
+ ', ` DEVELOP_QUOTIENT_BITS(incr($1), `eval(2*$2-1)')')
+ ifelse($1, 1, `9:')')
+
+#include <machine/asm.h>
+#include <machine/trap.h>
+
+FUNC(NAME)
+ifelse(S, `true',
+` ! compute sign of result; if neither is negative, no problem
+ orcc divisor, dividend, %g0 ! either negative?
+ bge 2f ! no, go do the divide
+ ifelse(OP, `div',
+ `xor divisor, dividend, SIGN',
+ `mov dividend, SIGN') ! compute sign in any case
+ tst divisor
+ bge 1f
+ tst dividend
+ ! divisor is definitely negative; dividend might also be negative
+ bge 2f ! if dividend not negative...
+ neg divisor ! in any case, make divisor nonneg
+1: ! dividend is negative, divisor is nonnegative
+ neg dividend ! make dividend nonnegative
+2:
+')
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc divisor, %g0, V
+ bnz 1f
+ mov dividend, R
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ t ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp R, V ! if divisor exceeds dividend, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr Q
+ sethi %hi(1 << (WORDSIZE - TOPBITS - 1)), T
+ cmp R, T
+ blu Lnot_really_big
+ clr ITER
+
+ ! `Here the dividend is >= 2^(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.'
+ 1:
+ cmp V, T
+ bgeu 3f
+ mov 1, SC
+ sll V, N, V
+ b 1b
+ inc ITER
+
+ ! Now compute SC.
+ 2: addcc V, V, V
+ bcc Lnot_too_big
+ inc SC
+
+ ! We get here if the divisor overflowed while shifting.
+ ! This means that R has the high-order bit set.
+ ! Restore V and subtract from R.
+ sll T, TOPBITS, T ! high order bit
+ srl V, 1, V ! rest of V
+ add V, T, V
+ b Ldo_single_div
+ dec SC
+
+ Lnot_too_big:
+ 3: cmp V, R
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! V > R: went too far: back up 1 step
+ ! srl V, 1, V
+ ! dec SC
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that R >= V, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if R >= 0. Because both R and V may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ deccc SC
+ bl Lend_regular_divide
+ nop
+ sub R, V, R
+ mov 1, Q
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll Q, 1, Q
+ bl 1f
+ srl V, 1, V
+ ! R >= 0
+ sub R, V, R
+ b 2f
+ inc Q
+ 1: ! R < 0
+ add R, V, R
+ dec Q
+ 2:
+ Lend_single_divloop:
+ deccc SC
+ bge Lsingle_divloop
+ tst R
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll V, N, V
+ cmp V, R
+ bleu 1b
+ inccc ITER
+ be Lgot_result
+ dec ITER
+
+ tst R ! set up for initial iteration
+Ldivloop:
+ sll Q, N, Q
+ DEVELOP_QUOTIENT_BITS(1, 0)
+Lend_regular_divide:
+ deccc ITER
+ bge Ldivloop
+ tst R
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ifelse(OP, `div',
+` dec Q
+', ` add R, divisor, R
+')
+
+Lgot_result:
+ifelse(S, `true',
+` ! check to see if answer should be < 0
+ tst SIGN
+ bl,a 1f
+ ifelse(OP, `div', `neg Q', `neg R')
+1:')
+ retl
+ ifelse(OP, `div', `mov Q, %o0', `mov R, %o0')
diff --git a/usr/klibc/arch/sparc/pipe.S b/usr/klibc/arch/sparc/pipe.S
new file mode 100644
index 0000000..e278bda
--- /dev/null
+++ b/usr/klibc/arch/sparc/pipe.S
@@ -0,0 +1,31 @@
+/*
+ * arch/sparc/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ .globl pipe
+ .type pipe,#function
+ .align 4
+pipe:
+ mov __NR_pipe, %g1
+ or %o0, 0, %g4
+ t 0x10
+ bcc 1f
+ nop
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0,[%g4]
+ retl
+ mov -1, %o0
+1:
+ st %o0,[%g4]
+ st %o1,[%g4+4]
+ retl
+ mov 0, %o0
+
+ .size pipe,.-pipe
diff --git a/usr/klibc/arch/sparc/setjmp.S b/usr/klibc/arch/sparc/setjmp.S
new file mode 100644
index 0000000..038ea78
--- /dev/null
+++ b/usr/klibc/arch/sparc/setjmp.S
@@ -0,0 +1,38 @@
+!
+! setjmp.S
+!
+! Basic setjmp/longjmp
+!
+! This code was based on the equivalent code in NetBSD
+!
+
+#include <machine/asm.h>
+#include <machine/trap.h>
+
+!
+! The jmp_buf contains the following entries:
+! sp
+! fp
+! pc
+!
+ENTRY(setjmp)
+ st %sp,[%o0+0] ! Callers stack pointer
+ st %o7,[%o0+4] ! Return pc
+ st %fp,[%o0+8] ! Frame pointer
+ retl ! Return
+ clr %o0 ! ...0
+
+ENTRY(longjmp)
+ sub %sp, 64, %sp ! set up a local stack frame
+0:
+ t ST_FLUSHWIN ! flush register windows out to memory
+ !
+ ! We restore the saved stack pointer to %fp, then issue
+ ! a restore instruction which will reload the register
+ ! window from the stack.
+ !
+ ld [%o0+4], %o7 /* restore return pc */
+ ld [%o0+0], %fp /* and stack pointer */
+
+ retl ! success, return %g6
+ restore %o1, 0, %o0
diff --git a/usr/klibc/arch/sparc/sigaction.c b/usr/klibc/arch/sparc/sigaction.c
new file mode 100644
index 0000000..5c31a52
--- /dev/null
+++ b/usr/klibc/arch/sparc/sigaction.c
@@ -0,0 +1,21 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+
+__extern void __sigreturn(void);
+__extern int ____rt_sigaction(int, const struct sigaction *, struct sigaction *,
+ void (*)(void), size_t);
+
+int __rt_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact, size_t size)
+{
+ void (*restorer)(void);
+
+ restorer = (act && act->sa_flags & SA_RESTORER)
+ ? (void (*)(void))((uintptr_t)act->sa_restorer - 8)
+ : NULL;
+ return ____rt_sigaction(sig, act, oact, restorer, size);
+}
diff --git a/usr/klibc/arch/sparc/smul.S b/usr/klibc/arch/sparc/smul.S
new file mode 100644
index 0000000..544ff6e
--- /dev/null
+++ b/usr/klibc/arch/sparc/smul.S
@@ -0,0 +1,160 @@
+/* $NetBSD: mul.S,v 1.3 1997/07/16 14:37:42 christos Exp $ */
+
+/*
+ * 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: mul.s,v 1.5 92/06/25 13:24:03 torek Exp
+ */
+
+#include <machine/asm.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ .asciz "@(#)mul.s 8.1 (Berkeley) 6/4/93"
+#else
+ RCSID("$NetBSD: mul.S,v 1.3 1997/07/16 14:37:42 christos Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Signed multiply, from Appendix E of the Sparc Version 8
+ * Architecture Manual.
+ *
+ * Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the upper 32 bits of
+ * the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies.
+ */
+
+FUNC(.mul)
+ mov %o0, %y ! multiplier -> Y
+ andncc %o0, 0xfff, %g0 ! test bits 12..31
+ be Lmul_shortway ! if zero, can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
+
+ /*
+ * Long multiply. 32 steps, followed by a final shift step.
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %o1, %o4 ! 13
+ mulscc %o4, %o1, %o4 ! 14
+ mulscc %o4, %o1, %o4 ! 15
+ mulscc %o4, %o1, %o4 ! 16
+ mulscc %o4, %o1, %o4 ! 17
+ mulscc %o4, %o1, %o4 ! 18
+ mulscc %o4, %o1, %o4 ! 19
+ mulscc %o4, %o1, %o4 ! 20
+ mulscc %o4, %o1, %o4 ! 21
+ mulscc %o4, %o1, %o4 ! 22
+ mulscc %o4, %o1, %o4 ! 23
+ mulscc %o4, %o1, %o4 ! 24
+ mulscc %o4, %o1, %o4 ! 25
+ mulscc %o4, %o1, %o4 ! 26
+ mulscc %o4, %o1, %o4 ! 27
+ mulscc %o4, %o1, %o4 ! 28
+ mulscc %o4, %o1, %o4 ! 29
+ mulscc %o4, %o1, %o4 ! 30
+ mulscc %o4, %o1, %o4 ! 31
+ mulscc %o4, %o1, %o4 ! 32
+ mulscc %o4, %g0, %o4 ! final shift
+
+ ! If %o0 was negative, the result is
+ ! (%o0 * %o1) + (%o1 << 32))
+ ! We fix that here.
+
+ tst %o0
+ bge 1f
+ rd %y, %o0
+
+ ! %o0 was indeed negative; fix upper 32 bits of result by subtracting
+ ! %o1 (i.e., return %o4 - %o1 in %o1).
+ retl
+ sub %o4, %o1, %o1
+
+1:
+ retl
+ mov %o4, %o1
+
+Lmul_shortway:
+ /*
+ * Short multiply. 12 steps, followed by a final shift step.
+ * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+ * but there is no problem with %o0 being negative (unlike above).
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %g0, %o4 ! final shift
+
+ /*
+ * %o4 has 20 of the bits that should be in the low part of the
+ * result; %y has the bottom 12 (as %y's top 12). That is:
+ *
+ * %o4 %y
+ * +----------------+----------------+
+ * | -12- | -20- | -12- | -20- |
+ * +------(---------+------)---------+
+ * --hi-- ----low-part----
+ *
+ * The upper 12 bits of %o4 should be sign-extended to form the
+ * high part of the product (i.e., highpart = %o4 >> 20).
+ */
+
+ rd %y, %o5
+ sll %o4, 12, %o0 ! shift middle bits left 12
+ srl %o5, 20, %o5 ! shift low bits right 20, zero fill at left
+ or %o5, %o0, %o0 ! construct low part of result
+ retl
+ sra %o4, 20, %o1 ! ... and extract high part of result
diff --git a/usr/klibc/arch/sparc/syscall.S b/usr/klibc/arch/sparc/syscall.S
new file mode 100644
index 0000000..52a8583
--- /dev/null
+++ b/usr/klibc/arch/sparc/syscall.S
@@ -0,0 +1,21 @@
+/*
+ * arch/sparc/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+#include <machine/asm.h>
+
+ .globl __syscall_common
+ .type __syscall_common,#function
+ .align 4
+__syscall_common:
+ t 0x10
+ bcc 1f
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0,[%g4]
+ mov -1, %o0
+1:
+ retl
+ nop
diff --git a/usr/klibc/arch/sparc/sysfork.S b/usr/klibc/arch/sparc/sysfork.S
new file mode 100644
index 0000000..3787b94
--- /dev/null
+++ b/usr/klibc/arch/sparc/sysfork.S
@@ -0,0 +1,27 @@
+/*
+ * arch/sparc/sysfork.S
+ *
+ * The fork and vfork system calls are special on sparc[64]:
+ * they return the "other process" pid in %o0 and the
+ * "is child" flag in %o1
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+#include <machine/asm.h>
+
+ .globl __syscall_forkish
+ .type __syscall_forkish,#function
+ .align 4
+__syscall_forkish:
+ t 0x10
+ sub %o1, 1, %o1
+ bcc,a 1f
+ and %o0, %o1, %o0
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0,[%g4]
+ mov -1, %o0
+1:
+ retl
+ nop
diff --git a/usr/klibc/arch/sparc/sysstub.ph b/usr/klibc/arch/sparc/sysstub.ph
new file mode 100644
index 0000000..d8cedb5
--- /dev/null
+++ b/usr/klibc/arch/sparc/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/sparc32/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tb __syscall_${stype}\n";
+ print OUT "\t mov\t__NR_${sname}, %g1\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/sparc/umul.S b/usr/klibc/arch/sparc/umul.S
new file mode 100644
index 0000000..6a7193d
--- /dev/null
+++ b/usr/klibc/arch/sparc/umul.S
@@ -0,0 +1,193 @@
+/* $NetBSD: umul.S,v 1.3 1997/07/16 14:37:44 christos Exp $ */
+
+/*
+ * 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: umul.s,v 1.4 92/06/25 13:24:05 torek Exp
+ */
+
+#include <machine/asm.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+ .asciz "@(#)umul.s 8.1 (Berkeley) 6/4/93"
+#else
+ RCSID("$NetBSD: umul.S,v 1.3 1997/07/16 14:37:44 christos Exp $")
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
+ * upper 32 bits of the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies. Short
+ * multiplies require 25 instruction cycles, and long ones require
+ * 45 instruction cycles.
+ *
+ * On return, overflow has occurred (%o1 is not zero) if and only if
+ * the Z condition code is clear, allowing, e.g., the following:
+ *
+ * call .umul
+ * nop
+ * bnz overflow (or tnz)
+ */
+
+FUNC(.umul)
+ or %o0, %o1, %o4
+ mov %o0, %y ! multiplier -> Y
+ andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args
+ be Lmul_shortway ! if zero, can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
+
+ /*
+ * Long multiply. 32 steps, followed by a final shift step.
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %o1, %o4 ! 13
+ mulscc %o4, %o1, %o4 ! 14
+ mulscc %o4, %o1, %o4 ! 15
+ mulscc %o4, %o1, %o4 ! 16
+ mulscc %o4, %o1, %o4 ! 17
+ mulscc %o4, %o1, %o4 ! 18
+ mulscc %o4, %o1, %o4 ! 19
+ mulscc %o4, %o1, %o4 ! 20
+ mulscc %o4, %o1, %o4 ! 21
+ mulscc %o4, %o1, %o4 ! 22
+ mulscc %o4, %o1, %o4 ! 23
+ mulscc %o4, %o1, %o4 ! 24
+ mulscc %o4, %o1, %o4 ! 25
+ mulscc %o4, %o1, %o4 ! 26
+ mulscc %o4, %o1, %o4 ! 27
+ mulscc %o4, %o1, %o4 ! 28
+ mulscc %o4, %o1, %o4 ! 29
+ mulscc %o4, %o1, %o4 ! 30
+ mulscc %o4, %o1, %o4 ! 31
+ mulscc %o4, %o1, %o4 ! 32
+ mulscc %o4, %g0, %o4 ! final shift
+
+
+ /*
+ * Normally, with the shift-and-add approach, if both numbers are
+ * positive you get the correct result. WIth 32-bit two's-complement
+ * numbers, -x is represented as
+ *
+ * x 32
+ * ( 2 - ------ ) mod 2 * 2
+ * 32
+ * 2
+ *
+ * (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s,
+ * we can treat this as if the radix point were just to the left
+ * of the sign bit (multiply by 2^32), and get
+ *
+ * -x = (2 - x) mod 2
+ *
+ * Then, ignoring the `mod 2's for convenience:
+ *
+ * x * y = xy
+ * -x * y = 2y - xy
+ * x * -y = 2x - xy
+ * -x * -y = 4 - 2x - 2y + xy
+ *
+ * For signed multiplies, we subtract (x << 32) from the partial
+ * product to fix this problem for negative multipliers (see mul.s).
+ * Because of the way the shift into the partial product is calculated
+ * (N xor V), this term is automatically removed for the multiplicand,
+ * so we don't have to adjust.
+ *
+ * But for unsigned multiplies, the high order bit wasn't a sign bit,
+ * and the correction is wrong. So for unsigned multiplies where the
+ * high order bit is one, we end up with xy - (y << 32). To fix it
+ * we add y << 32.
+ */
+ tst %o1
+ bl,a 1f ! if %o1 < 0 (high order bit = 1),
+ add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half)
+1: rd %y, %o0 ! get lower half of product
+ retl
+ addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0
+
+Lmul_shortway:
+ /*
+ * Short multiply. 12 steps, followed by a final shift step.
+ * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+ * but there is no problem with %o0 being negative (unlike above),
+ * and overflow is impossible (the answer is at most 24 bits long).
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %g0, %o4 ! final shift
+
+ /*
+ * %o4 has 20 of the bits that should be in the result; %y has
+ * the bottom 12 (as %y's top 12). That is:
+ *
+ * %o4 %y
+ * +----------------+----------------+
+ * | -12- | -20- | -12- | -20- |
+ * +------(---------+------)---------+
+ * -----result-----
+ *
+ * The 12 bits of %o4 left of the `result' area are all zero;
+ * in fact, all top 20 bits of %o4 are zero.
+ */
+
+ rd %y, %o5
+ sll %o4, 12, %o0 ! shift middle bits left 12
+ srl %o5, 20, %o5 ! shift low bits right 20
+ or %o5, %o0, %o0
+ retl
+ addcc %g0, %g0, %o1 ! %o1 = zero, and set Z
diff --git a/usr/klibc/arch/sparc64/Kbuild b/usr/klibc/arch/sparc64/Kbuild
new file mode 100644
index 0000000..dbc6c65
--- /dev/null
+++ b/usr/klibc/arch/sparc64/Kbuild
@@ -0,0 +1,8 @@
+#
+# klibc files for sparc64
+#
+
+klib-y := pipe.o setjmp.o sigaction.o syscall.o sysfork.o
+
+always := crt0.o
+targets := crt0.o
diff --git a/usr/klibc/arch/sparc64/MCONFIG b/usr/klibc/arch/sparc64/MCONFIG
new file mode 100644
index 0000000..d8c878a
--- /dev/null
+++ b/usr/klibc/arch/sparc64/MCONFIG
@@ -0,0 +1,24 @@
+# -*- makefile -*-
+#
+# arch/sparc64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+KLIBCARCHREQFLAGS = -m64 -D__sparc64__
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE = 64
+
+KLIBCLDFLAGS = -m elf64_sparc
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# Normal binaries start at 1 MB; the linker wants 1 MB alignment,
+# and call instructions have a 30-bit signed offset, << 2.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x80000000
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/sparc64/crt0.S b/usr/klibc/arch/sparc64/crt0.S
new file mode 100644
index 0000000..5faee7c
--- /dev/null
+++ b/usr/klibc/arch/sparc64/crt0.S
@@ -0,0 +1,2 @@
+#define TARGET_PTR_SIZE 64
+#include "../sparc/crt0i.S"
diff --git a/usr/klibc/arch/sparc64/pipe.S b/usr/klibc/arch/sparc64/pipe.S
new file mode 100644
index 0000000..cb5c2c7
--- /dev/null
+++ b/usr/klibc/arch/sparc64/pipe.S
@@ -0,0 +1,31 @@
+/*
+ * arch/sparc64/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+ .globl pipe
+ .type pipe,#function
+ .align 4
+pipe:
+ mov __NR_pipe, %g1
+ or %o0, 0, %g4
+ t 0x6d
+ bcc %xcc, 1f
+ nop
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0,[%g4]
+ retl
+ mov -1, %o0
+1:
+ st %o0,[%g4]
+ st %o1,[%g4+4]
+ retl
+ mov 0, %o0
+
+ .size pipe,.-pipe
diff --git a/usr/klibc/arch/sparc64/setjmp.S b/usr/klibc/arch/sparc64/setjmp.S
new file mode 100644
index 0000000..75a6a68
--- /dev/null
+++ b/usr/klibc/arch/sparc64/setjmp.S
@@ -0,0 +1,55 @@
+!
+! setjmp.S
+!
+! Basic setjmp/longjmp
+!
+! This code was based on the equivalent code in NetBSD
+!
+
+!
+! The jmp_buf contains the following entries:
+! sp
+! fp
+! pc
+!
+ .text
+ .align 4
+ .global setjmp
+ .type setjmp, @function
+setjmp:
+ stx %sp,[%o0+0] ! Callers stack pointer
+ stx %o7,[%o0+8] ! Return pc
+ stx %fp,[%o0+16] ! Frame pointer
+ retl ! Return
+ clr %o0 ! ...0
+
+ .size setjmp,.-setjmp
+
+
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ mov %o1, %g4 ! save return value
+ mov %o0, %g1 ! save target
+ ldx [%g1+16],%g5 ! get callers frame
+1:
+ cmp %fp, %g5 ! compare against desired frame
+ bl,a 1b ! if below...
+ restore ! pop frame and loop
+ be,a 2f ! if there...
+ ldx [%g1+0],%o2 ! fetch return %sp
+
+.Lbotch:
+ unimp 0 ! ... error ...
+
+2:
+ cmp %o2, %sp ! %sp must not decrease
+ bl .Lbotch
+ nop
+ mov %o2, %sp ! it is OK, put it in place
+
+ ldx [%g1+8],%o3 ! fetch %pc
+ jmp %o3 + 8 ! if sucess...
+ mov %g4,%o0 ! return %g4
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/sparc64/sigaction.c b/usr/klibc/arch/sparc64/sigaction.c
new file mode 100644
index 0000000..5c31a52
--- /dev/null
+++ b/usr/klibc/arch/sparc64/sigaction.c
@@ -0,0 +1,21 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+
+__extern void __sigreturn(void);
+__extern int ____rt_sigaction(int, const struct sigaction *, struct sigaction *,
+ void (*)(void), size_t);
+
+int __rt_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact, size_t size)
+{
+ void (*restorer)(void);
+
+ restorer = (act && act->sa_flags & SA_RESTORER)
+ ? (void (*)(void))((uintptr_t)act->sa_restorer - 8)
+ : NULL;
+ return ____rt_sigaction(sig, act, oact, restorer, size);
+}
diff --git a/usr/klibc/arch/sparc64/syscall.S b/usr/klibc/arch/sparc64/syscall.S
new file mode 100644
index 0000000..c84c9ae
--- /dev/null
+++ b/usr/klibc/arch/sparc64/syscall.S
@@ -0,0 +1,20 @@
+/*
+ * arch/sparc64/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+#include <machine/asm.h>
+
+ .globl __syscall_common
+ .type __syscall_common,#function
+ .align 4
+__syscall_common:
+ t 0x6d
+ bcc %xcc, 1f
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0,[%g4]
+1:
+ retl
+ movcs %xcc, -1, %o0
diff --git a/usr/klibc/arch/sparc64/sysfork.S b/usr/klibc/arch/sparc64/sysfork.S
new file mode 100644
index 0000000..a0c1334
--- /dev/null
+++ b/usr/klibc/arch/sparc64/sysfork.S
@@ -0,0 +1,28 @@
+/*
+ * arch/sparc64/sysfork.S
+ *
+ * The fork and vfork system calls are special on sparc[64]:
+ * they return the "other process" pid in %o0 and the
+ * "is child" flag in %o1
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+#include <machine/asm.h>
+
+ .globl __syscall_forkish
+ .type __syscall_forkish,#function
+ .align 4
+__syscall_forkish:
+ t 0x6d
+ sub %o1, 1, %o1
+ bcc,a %xcc, 1f
+ and %o0, %o1, %o0
+ PIC_PROLOGUE(%g1,%g4)
+ SET(errno,%g1,%g4)
+ st %o0, [%g4]
+ retl
+ mov -1, %o0
+1:
+ retl
+ nop
diff --git a/usr/klibc/arch/sparc64/sysstub.ph b/usr/klibc/arch/sparc64/sysstub.ph
new file mode 100644
index 0000000..deeb88c
--- /dev/null
+++ b/usr/klibc/arch/sparc64/sysstub.ph
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/sparc64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tb __syscall_${stype}\n";
+ print OUT "\t mov\t__NR_${sname}, %g1\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/x86_64/Kbuild b/usr/klibc/arch/x86_64/Kbuild
new file mode 100644
index 0000000..3f69c5b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/Kbuild
@@ -0,0 +1,8 @@
+# -*- makefile -*-
+#
+# klibc files for x86_64
+
+always := crt0.o
+targets := crt0.o
+
+klib-y := setjmp.o syscall.o sigreturn.o vfork.o
diff --git a/usr/klibc/arch/x86_64/MCONFIG b/usr/klibc/arch/x86_64/MCONFIG
new file mode 100644
index 0000000..70d690e
--- /dev/null
+++ b/usr/klibc/arch/x86_64/MCONFIG
@@ -0,0 +1,43 @@
+# -*- makefile -*-
+#
+# arch/x86-64/MCONFIG
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+# Blatantly copied and modified from i386 version by Mats Petersson, AMD.
+#
+
+#
+# NOTE: -fno-asynchronous-unwind-tables produce significantly smaller
+# binaries (20% smaller), but makes the code completely useless for
+# debugging using gdb.
+#
+KLIBCARCHREQFLAGS = -m64
+KLIBCOPTFLAGS += -Os -fomit-frame-pointer -mno-sse \
+ $(call cc-option,-falign-functions=1, ) \
+ $(call cc-option,-falign-jumps=1, ) \
+ $(call cc-option,-falign-loops=1, )
+ifeq ($(DEBUG),y)
+KLIBCOPTFLAGS += -g
+else
+KLIBCOPTFLAGS += -fno-asynchronous-unwind-tables
+endif
+KLIBCBITSIZE = 64
+KLIBCLDFLAGS = -m elf_x86_64 $(LD_IMAGE_BASE_OPT) 0x00400000
+
+# Extra linkflags when building the shared version of the library
+# This address needs to be reachable using normal inter-module
+# calls, and work on the memory models for this architecture
+# 2 MB - normal binaries start at 4 MB
+#
+# binutils now uses max-page-size=0x200000 by default, which pushes
+# klibc.so data over the 4 MB mark, overlapping the executable.
+# The old default was max-page-size=0x100000, but that also results
+# in a broken layout with binutils 2.30. Since there's no
+# architectural page size betwen 4 KB and 2MB, set it to 4 KB.
+KLIBCSHAREDFLAGS = $(LD_IMAGE_BASE_OPT) 0x00200000 -z max-page-size=0x1000
+
+# Kernel has never used stack trampolines
+KLIBCEXECSTACK := n
diff --git a/usr/klibc/arch/x86_64/crt0.S b/usr/klibc/arch/x86_64/crt0.S
new file mode 100644
index 0000000..6a5f335
--- /dev/null
+++ b/usr/klibc/arch/x86_64/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/x86_64/crt0.S
+#
+# Does arch-specific initialization and invokes __libc_init
+# with the appropriate arguments.
+#
+# See __static_init.c or __shared_init.c for the expected
+# arguments.
+#
+
+ .text
+ .align 4
+ .type _start,@function
+ .globl _start
+_start:
+ movq %rsp,%rdi # Offset of the ELF data structure
+ movq %rdx,%rsi # The atexit() pointer (if any)
+ call __libc_init
+ # We should never get here...
+ hlt
+
+ .size _start,.-_start
diff --git a/usr/klibc/arch/x86_64/setjmp.S b/usr/klibc/arch/x86_64/setjmp.S
new file mode 100644
index 0000000..45f547b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/setjmp.S
@@ -0,0 +1,54 @@
+#
+# arch/x86_64/setjmp.S
+#
+# setjmp/longjmp for the x86-64 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+# %rbx
+# %rsp (post-return)
+# %rbp
+# %r12
+# %r13
+# %r14
+# %r15
+# <return address>
+#
+
+ .text
+ .align 4
+ .globl setjmp
+ .type setjmp, @function
+setjmp:
+ pop %rsi # Return address, and adjust the stack
+ xorl %eax,%eax # Return value
+ movq %rbx,(%rdi)
+ movq %rsp,8(%rdi) # Post-return %rsp!
+ push %rsi # Make the call/return stack happy
+ movq %rbp,16(%rdi)
+ movq %r12,24(%rdi)
+ movq %r13,32(%rdi)
+ movq %r14,40(%rdi)
+ movq %r15,48(%rdi)
+ movq %rsi,56(%rdi) # Return address
+ ret
+
+ .size setjmp,.-setjmp
+
+ .text
+ .align 4
+ .globl longjmp
+ .type longjmp, @function
+longjmp:
+ movl %esi,%eax # Return value (int)
+ movq (%rdi),%rbx
+ movq 8(%rdi),%rsp
+ movq 16(%rdi),%rbp
+ movq 24(%rdi),%r12
+ movq 32(%rdi),%r13
+ movq 40(%rdi),%r14
+ movq 48(%rdi),%r15
+ jmp *56(%rdi)
+
+ .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/x86_64/sigreturn.S b/usr/klibc/arch/x86_64/sigreturn.S
new file mode 100644
index 0000000..46a5a0b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/sigreturn.S
@@ -0,0 +1,15 @@
+/*
+ * arch/x86_64/sigreturn.S
+ */
+
+#include <asm/unistd.h>
+
+ .text
+ .align 4
+ .globl __sigreturn
+ .type __sigreturn,@function
+__sigreturn:
+ movl $__NR_rt_sigreturn,%eax
+ syscall
+
+ .size __sigreturn,.-__sigreturn
diff --git a/usr/klibc/arch/x86_64/syscall.S b/usr/klibc/arch/x86_64/syscall.S
new file mode 100644
index 0000000..1797797
--- /dev/null
+++ b/usr/klibc/arch/x86_64/syscall.S
@@ -0,0 +1,28 @@
+/*
+ * arch/x86-64/syscall.S
+ *
+ * Common tail-handling code for system calls.
+ *
+ * The arguments are in the standard argument registers; the system
+ * call number in %eax.
+ */
+ .text
+ .align 4
+ .globl __syscall_common
+ .type __syscall_common,@function
+__syscall_common:
+ movq %rcx,%r10 # The kernel uses %r10 istf %rcx
+ syscall
+
+ cmpq $-4095,%rax
+ jnb 1f
+ ret
+
+ # Error return, must set errno
+1:
+ negl %eax
+ movl %eax,errno(%rip) # errno is type int, so 32 bits
+ orq $-1,%rax # orq $-1 smaller than movq $-1
+ ret
+
+ .size __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/x86_64/sysstub.ph b/usr/klibc/arch/x86_64/sysstub.ph
new file mode 100644
index 0000000..e2d797b
--- /dev/null
+++ b/usr/klibc/arch/x86_64/sysstub.ph
@@ -0,0 +1,23 @@
+# -*- perl -*-
+#
+# arch/x86_64/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tmovl \$__NR_${sname},%eax\n"; # Zero-extends to 64 bits
+ print OUT "\tjmp __syscall_common\n";
+ print OUT "\t.size ${fname},.-${fname}\n";
+ close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/x86_64/vfork.S b/usr/klibc/arch/x86_64/vfork.S
new file mode 100644
index 0000000..e1c8090
--- /dev/null
+++ b/usr/klibc/arch/x86_64/vfork.S
@@ -0,0 +1,26 @@
+#
+# usr/klibc/arch/x86_64/vfork.S
+#
+# vfork is nasty - there must be nothing at all on the stack above
+# the stack frame of the enclosing function.
+#
+
+#include <asm/unistd.h>
+
+ .text
+ .align 4
+ .globl vfork
+ .type vfork, @function
+vfork:
+ pop %rdx /* Return address */
+ movl $__NR_vfork, %eax
+ syscall
+ push %rdx
+ cmpq $-4095, %rax
+ jae 1f
+ ret
+1:
+ negl %eax
+ movl %eax, errno(%rip)
+ orq $-1, %rax
+ ret
diff --git a/usr/klibc/asprintf.c b/usr/klibc/asprintf.c
new file mode 100644
index 0000000..42f3aa2
--- /dev/null
+++ b/usr/klibc/asprintf.c
@@ -0,0 +1,19 @@
+/*
+ * asprintf.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int asprintf(char **bufp, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vasprintf(bufp, format, ap);
+ va_end(ap);
+
+ return rv;
+}
diff --git a/usr/klibc/assert.c b/usr/klibc/assert.c
new file mode 100644
index 0000000..cca4129
--- /dev/null
+++ b/usr/klibc/assert.c
@@ -0,0 +1,14 @@
+/*
+ * assert.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <klibc/compiler.h>
+
+__noreturn __assert_fail(const char *expr, const char *file, unsigned int line)
+{
+ printf("Assertion %s failed, file %s, line %u\n", expr, file, line);
+ abort();
+}
diff --git a/usr/klibc/atexit.c b/usr/klibc/atexit.c
new file mode 100644
index 0000000..af1b461
--- /dev/null
+++ b/usr/klibc/atexit.c
@@ -0,0 +1,10 @@
+/*
+ * atexit.c
+ */
+
+#include <stdlib.h>
+
+int atexit(void (*fctn) (void))
+{
+ return on_exit((void (*)(int, void *))fctn, NULL);
+}
diff --git a/usr/klibc/atexit.h b/usr/klibc/atexit.h
new file mode 100644
index 0000000..5018689
--- /dev/null
+++ b/usr/klibc/atexit.h
@@ -0,0 +1,18 @@
+/*
+ * atexit.h
+ *
+ * atexit()/on_exit() internal definitions
+ */
+
+#ifndef ATEXIT_H
+#define ATEXIT_H
+
+struct atexit {
+ void (*fctn) (int, void *);
+ void *arg; /* on_exit() parameter */
+ struct atexit *next;
+};
+
+extern struct atexit *__atexit_list;
+
+#endif /* ATEXIT_H */
diff --git a/usr/klibc/atoi.c b/usr/klibc/atoi.c
new file mode 100644
index 0000000..a6ec0bf
--- /dev/null
+++ b/usr/klibc/atoi.c
@@ -0,0 +1,3 @@
+#define TYPE int
+#define NAME atoi
+#include "atox.c"
diff --git a/usr/klibc/atol.c b/usr/klibc/atol.c
new file mode 100644
index 0000000..e65484e
--- /dev/null
+++ b/usr/klibc/atol.c
@@ -0,0 +1,3 @@
+#define TYPE long
+#define NAME atol
+#include "atox.c"
diff --git a/usr/klibc/atoll.c b/usr/klibc/atoll.c
new file mode 100644
index 0000000..25df79e
--- /dev/null
+++ b/usr/klibc/atoll.c
@@ -0,0 +1,3 @@
+#define TYPE long long
+#define NAME atoll
+#include "atox.c"
diff --git a/usr/klibc/atox.c b/usr/klibc/atox.c
new file mode 100644
index 0000000..c013bb4
--- /dev/null
+++ b/usr/klibc/atox.c
@@ -0,0 +1,14 @@
+/*
+ * atox.c
+ *
+ * atoi(), atol(), atoll()
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+TYPE NAME(const char *nptr)
+{
+ return (TYPE) strntoumax(nptr, (char **)NULL, 10, ~(size_t) 0);
+}
diff --git a/usr/klibc/brk.c b/usr/klibc/brk.c
new file mode 100644
index 0000000..df0bb7b
--- /dev/null
+++ b/usr/klibc/brk.c
@@ -0,0 +1,29 @@
+/* brk.c - Change data segment size */
+
+/* Written 2000 by Werner Almesberger */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "malloc.h"
+
+#if !_KLIBC_NO_MMU /* uClinux doesn't have brk() */
+
+char *__current_brk;
+
+/*
+ * The Linux brk() isn't what most people expect, so we call the
+ * system call __brk() and provide a wrapper.
+ */
+int brk(void *end_data_segment)
+{
+ char *new_brk;
+
+ new_brk = __brk(end_data_segment);
+ if (new_brk != end_data_segment)
+ return -1;
+ __current_brk = new_brk;
+ return 0;
+}
+
+#endif
diff --git a/usr/klibc/bsd_signal.c b/usr/klibc/bsd_signal.c
new file mode 100644
index 0000000..3d78d2c
--- /dev/null
+++ b/usr/klibc/bsd_signal.c
@@ -0,0 +1,14 @@
+/*
+ * bsd_signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t bsd_signal(int signum, __sighandler_t handler)
+{
+ /* BSD signal() semantics */
+ return __signal(signum, handler, SA_RESTART);
+}
+
+__sighandler_t signal(int signum, __sighandler_t handler)
+ __alias("bsd_signal");
diff --git a/usr/klibc/bsearch.c b/usr/klibc/bsearch.c
new file mode 100644
index 0000000..1c8b07f
--- /dev/null
+++ b/usr/klibc/bsearch.c
@@ -0,0 +1,26 @@
+/*
+ * bsearch.c
+ */
+
+#include <stdlib.h>
+
+void *bsearch(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*cmp) (const void *, const void *))
+{
+ while (nmemb) {
+ size_t mididx = nmemb / 2;
+ const void *midobj = base + mididx * size;
+ int diff = cmp(key, midobj);
+
+ if (diff == 0)
+ return (void *)midobj;
+
+ if (diff > 0) {
+ base = midobj + size;
+ nmemb -= mididx + 1;
+ } else
+ nmemb = mididx;
+ }
+
+ return NULL;
+}
diff --git a/usr/klibc/bzero.c b/usr/klibc/bzero.c
new file mode 100644
index 0000000..aa1c1ff
--- /dev/null
+++ b/usr/klibc/bzero.c
@@ -0,0 +1,6 @@
+#include <string.h>
+
+void bzero(void *dst, size_t n)
+{
+ memset(dst, 0, n);
+}
diff --git a/usr/klibc/calloc.c b/usr/klibc/calloc.c
new file mode 100644
index 0000000..4a81cda
--- /dev/null
+++ b/usr/klibc/calloc.c
@@ -0,0 +1,18 @@
+/*
+ * calloc.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *calloc(size_t nmemb, size_t size)
+{
+ unsigned long prod;
+
+ if (__builtin_umull_overflow(nmemb, size, &prod)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return zalloc(prod);
+}
diff --git a/usr/klibc/chmod.c b/usr/klibc/chmod.c
new file mode 100644
index 0000000..b5129e6
--- /dev/null
+++ b/usr/klibc/chmod.c
@@ -0,0 +1,13 @@
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_chmod
+
+int chmod(const char *path, mode_t mode)
+{
+ return fchmodat(AT_FDCWD, path, mode, 0);
+}
+
+#endif /* __NR_chmod */
diff --git a/usr/klibc/chown.c b/usr/klibc/chown.c
new file mode 100644
index 0000000..089cfc5
--- /dev/null
+++ b/usr/klibc/chown.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_chown
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+ return fchownat(AT_FDCWD, path, owner, group, 0);
+}
+
+#endif /* __NR_chown */
diff --git a/usr/klibc/clearenv.c b/usr/klibc/clearenv.c
new file mode 100644
index 0000000..7c2435e
--- /dev/null
+++ b/usr/klibc/clearenv.c
@@ -0,0 +1,17 @@
+/*
+ * clearenv.c
+ *
+ * Empty the environment
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "env.h"
+
+/* Note: if environ has been malloc'd, it will be freed on the next
+ setenv() or putenv() */
+int clearenv(void)
+{
+ environ = (char **)__null_environ;
+ return 0;
+}
diff --git a/usr/klibc/clock_nanosleep.c b/usr/klibc/clock_nanosleep.c
new file mode 100644
index 0000000..b4fd1e2
--- /dev/null
+++ b/usr/klibc/clock_nanosleep.c
@@ -0,0 +1,17 @@
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+extern int __clock_nanosleep(clockid_t, int,
+ const struct timespec *, struct timespec *);
+
+/*
+ * POSIX says this has to return a positive error code, but the system
+ * call returns error codes in the usual way.
+ */
+int clock_nanosleep(clockid_t clock_id, int flags,
+ const struct timespec *request, struct timespec *remain)
+{
+ return __clock_nanosleep(clock_id, flags, request, remain) ?
+ errno : 0;
+}
diff --git a/usr/klibc/closelog.c b/usr/klibc/closelog.c
new file mode 100644
index 0000000..0437710
--- /dev/null
+++ b/usr/klibc/closelog.c
@@ -0,0 +1,18 @@
+/*
+ * closelog.c
+ */
+
+#include <syslog.h>
+#include <unistd.h>
+
+extern int __syslog_fd;
+
+void closelog(void)
+{
+ int logfd = __syslog_fd;
+
+ if (logfd != -1) {
+ close(logfd);
+ __syslog_fd = -1;
+ }
+}
diff --git a/usr/klibc/creat.c b/usr/klibc/creat.c
new file mode 100644
index 0000000..b503bca
--- /dev/null
+++ b/usr/klibc/creat.c
@@ -0,0 +1,12 @@
+/*
+ * creat.c
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int creat(const char *pathname, mode_t mode)
+{
+ return open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
diff --git a/usr/klibc/ctype/ctypefunc.h b/usr/klibc/ctype/ctypefunc.h
new file mode 100644
index 0000000..f9e247d
--- /dev/null
+++ b/usr/klibc/ctype/ctypefunc.h
@@ -0,0 +1,13 @@
+/*
+ * ctype/ctype.h
+ *
+ * Common header for out-of-line ctype functions
+ */
+
+#define __CTYPE_NO_INLINE
+#include <ctype.h>
+
+#define CTYPEFUNC(X) \
+ int X(int c) { \
+ return __ctype_##X(c); \
+ }
diff --git a/usr/klibc/ctype/isalnum.c b/usr/klibc/ctype/isalnum.c
new file mode 100644
index 0000000..57af18b
--- /dev/null
+++ b/usr/klibc/ctype/isalnum.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isalnum)
diff --git a/usr/klibc/ctype/isalpha.c b/usr/klibc/ctype/isalpha.c
new file mode 100644
index 0000000..8f2effe
--- /dev/null
+++ b/usr/klibc/ctype/isalpha.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isalpha)
diff --git a/usr/klibc/ctype/isascii.c b/usr/klibc/ctype/isascii.c
new file mode 100644
index 0000000..6a974d5
--- /dev/null
+++ b/usr/klibc/ctype/isascii.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isascii)
diff --git a/usr/klibc/ctype/isblank.c b/usr/klibc/ctype/isblank.c
new file mode 100644
index 0000000..7728550
--- /dev/null
+++ b/usr/klibc/ctype/isblank.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isblank)
diff --git a/usr/klibc/ctype/iscntrl.c b/usr/klibc/ctype/iscntrl.c
new file mode 100644
index 0000000..81db804
--- /dev/null
+++ b/usr/klibc/ctype/iscntrl.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(iscntrl)
diff --git a/usr/klibc/ctype/isdigit.c b/usr/klibc/ctype/isdigit.c
new file mode 100644
index 0000000..41a39d9
--- /dev/null
+++ b/usr/klibc/ctype/isdigit.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isdigit)
diff --git a/usr/klibc/ctype/isgraph.c b/usr/klibc/ctype/isgraph.c
new file mode 100644
index 0000000..e5b83d1
--- /dev/null
+++ b/usr/klibc/ctype/isgraph.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isgraph)
diff --git a/usr/klibc/ctype/islower.c b/usr/klibc/ctype/islower.c
new file mode 100644
index 0000000..9e179ae
--- /dev/null
+++ b/usr/klibc/ctype/islower.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(islower)
diff --git a/usr/klibc/ctype/isprint.c b/usr/klibc/ctype/isprint.c
new file mode 100644
index 0000000..9c6a351
--- /dev/null
+++ b/usr/klibc/ctype/isprint.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isprint)
diff --git a/usr/klibc/ctype/ispunct.c b/usr/klibc/ctype/ispunct.c
new file mode 100644
index 0000000..36b5258
--- /dev/null
+++ b/usr/klibc/ctype/ispunct.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(ispunct)
diff --git a/usr/klibc/ctype/isspace.c b/usr/klibc/ctype/isspace.c
new file mode 100644
index 0000000..aed06c8
--- /dev/null
+++ b/usr/klibc/ctype/isspace.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isspace)
diff --git a/usr/klibc/ctype/isupper.c b/usr/klibc/ctype/isupper.c
new file mode 100644
index 0000000..70a139b
--- /dev/null
+++ b/usr/klibc/ctype/isupper.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isupper)
diff --git a/usr/klibc/ctype/isxdigit.c b/usr/klibc/ctype/isxdigit.c
new file mode 100644
index 0000000..ab89c1f
--- /dev/null
+++ b/usr/klibc/ctype/isxdigit.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(isxdigit)
diff --git a/usr/klibc/ctype/tolower.c b/usr/klibc/ctype/tolower.c
new file mode 100644
index 0000000..24ca72b
--- /dev/null
+++ b/usr/klibc/ctype/tolower.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(tolower)
diff --git a/usr/klibc/ctype/toupper.c b/usr/klibc/ctype/toupper.c
new file mode 100644
index 0000000..15763f7
--- /dev/null
+++ b/usr/klibc/ctype/toupper.c
@@ -0,0 +1,2 @@
+#include "ctypefunc.h"
+CTYPEFUNC(toupper)
diff --git a/usr/klibc/ctypes.c b/usr/klibc/ctypes.c
new file mode 100644
index 0000000..deb566a
--- /dev/null
+++ b/usr/klibc/ctypes.c
@@ -0,0 +1,284 @@
+/*
+ * ctypes.c
+ *
+ * This is the array that defines <ctype.h> classes.
+ * This assumes ISO 8859-1.
+ */
+
+#include <ctype.h>
+
+const unsigned char __ctypes[257] = {
+ 0, /* EOF */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl | __ctype_space, /* BS */
+ __ctype_cntrl | __ctype_space, /* TAB */
+ __ctype_cntrl | __ctype_space, /* LF */
+ __ctype_cntrl | __ctype_space, /* VT */
+ __ctype_cntrl | __ctype_space, /* FF */
+ __ctype_cntrl | __ctype_space, /* CR */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_print | __ctype_space, /* space */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_digit | __ctype_xdigit, /* digit */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper | __ctype_xdigit, /* A-F */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_upper, /* G-Z */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower | __ctype_xdigit, /* a-f */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_lower, /* g-z */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+ __ctype_cntrl, /* control character */
+
+ __ctype_print | __ctype_space, /* NBSP */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_punct, /* punctuation */
+
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_upper, /* upper accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_punct, /* punctuation */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+ __ctype_print | __ctype_lower, /* lower accented */
+};
diff --git a/usr/klibc/daemon.c b/usr/klibc/daemon.c
new file mode 100644
index 0000000..61b88dd
--- /dev/null
+++ b/usr/klibc/daemon.c
@@ -0,0 +1,35 @@
+/*
+ * daemon.c - "daemonize" a process
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int daemon(int nochdir, int noclose)
+{
+ int nullfd;
+ pid_t f;
+
+ if (!nochdir) {
+ if (chdir("/"))
+ return -1;
+ }
+
+ if (!noclose) {
+ if ((nullfd = open("/dev/null", O_RDWR)) < 0 ||
+ dup2(nullfd, 0) < 0 ||
+ dup2(nullfd, 1) < 0 ||
+ dup2(nullfd, 2) < 0)
+ return -1;
+ close(nullfd);
+ }
+
+ f = fork();
+ if (f < 0)
+ return -1;
+ else if (f > 0)
+ _exit(0);
+
+ return setsid();
+}
diff --git a/usr/klibc/dup2.c b/usr/klibc/dup2.c
new file mode 100644
index 0000000..67e2171
--- /dev/null
+++ b/usr/klibc/dup2.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_dup2
+
+int dup2(int fd, int fd2)
+{
+ return dup3(fd, fd2, 0);
+}
+
+#endif /* __NR_dup2 */
diff --git a/usr/klibc/endmntent.c b/usr/klibc/endmntent.c
new file mode 100644
index 0000000..419c317
--- /dev/null
+++ b/usr/klibc/endmntent.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <mntent.h>
+
+int endmntent(FILE *fp)
+{
+ if (fp)
+ fclose(fp);
+ return 1;
+}
diff --git a/usr/klibc/env.h b/usr/klibc/env.h
new file mode 100644
index 0000000..ae70be8
--- /dev/null
+++ b/usr/klibc/env.h
@@ -0,0 +1,10 @@
+#ifndef ENV_H
+#define ENV_H
+
+/* str should be a duplicated version of the input string;
+ len is the length of the key including the = sign */
+int __put_env(char *str, size_t len, int overwrite);
+
+extern char *const __null_environ[];
+
+#endif
diff --git a/usr/klibc/exec_l.c b/usr/klibc/exec_l.c
new file mode 100644
index 0000000..76b70df
--- /dev/null
+++ b/usr/klibc/exec_l.c
@@ -0,0 +1,59 @@
+/*
+ * exec_l.c
+ *
+ * Common implementation of execl() execle() execlp()
+ */
+
+#include <stdarg.h>
+#include <alloca.h>
+#include <unistd.h>
+
+int NAME(const char *path, const char *arg0, ...)
+{
+ va_list ap, cap;
+ int argc = 1, rv;
+ const char **argv, **argp;
+ const char *arg;
+ char *const *envp;
+
+ va_start(ap, arg0);
+ va_copy(cap, ap);
+
+ /* Count the number of arguments */
+ do {
+ arg = va_arg(cap, const char *);
+ argc++;
+ } while (arg);
+
+ va_end(cap);
+
+ /* Allocate memory for the pointer array */
+ argp = argv = alloca(argc * sizeof(const char *));
+ if (!argv) {
+ va_end(ap);
+ return -1;
+ }
+
+ /* Copy the list into an array */
+ *argp++ = arg0;
+ do {
+ *argp++ = arg = va_arg(ap, const char *);
+ } while (arg);
+
+#if EXEC_E
+ /* execle() takes one more argument for the environment pointer */
+ envp = va_arg(ap, char *const *);
+#else
+ envp = environ;
+#endif
+
+#if EXEC_P
+ rv = execvpe(path, (char * const *)argv, envp);
+#else
+ rv = execve(path, (char * const *)argv, envp);
+#endif
+
+ va_end(ap);
+
+ return rv;
+}
diff --git a/usr/klibc/execl.c b/usr/klibc/execl.c
new file mode 100644
index 0000000..4581113
--- /dev/null
+++ b/usr/klibc/execl.c
@@ -0,0 +1,8 @@
+/*
+ * execl.c
+ */
+
+#define NAME execl
+#define EXEC_P 0
+#define EXEC_E 0
+#include "exec_l.c"
diff --git a/usr/klibc/execle.c b/usr/klibc/execle.c
new file mode 100644
index 0000000..b073988
--- /dev/null
+++ b/usr/klibc/execle.c
@@ -0,0 +1,8 @@
+/*
+ * execle.c
+ */
+
+#define NAME execle
+#define EXEC_P 0
+#define EXEC_E 1
+#include "exec_l.c"
diff --git a/usr/klibc/execlp.c b/usr/klibc/execlp.c
new file mode 100644
index 0000000..65c9aa4
--- /dev/null
+++ b/usr/klibc/execlp.c
@@ -0,0 +1,8 @@
+/*
+ * execlp.c
+ */
+
+#define NAME execlp
+#define EXEC_P 1
+#define EXEC_E 0
+#include "exec_l.c"
diff --git a/usr/klibc/execlpe.c b/usr/klibc/execlpe.c
new file mode 100644
index 0000000..fef972f
--- /dev/null
+++ b/usr/klibc/execlpe.c
@@ -0,0 +1,8 @@
+/*
+ * execlpe.c
+ */
+
+#define NAME execlpe
+#define EXEC_P 1
+#define EXEC_E 1
+#include "exec_l.c"
diff --git a/usr/klibc/execv.c b/usr/klibc/execv.c
new file mode 100644
index 0000000..6894e79
--- /dev/null
+++ b/usr/klibc/execv.c
@@ -0,0 +1,10 @@
+/*
+ * execv.c
+ */
+
+#include <unistd.h>
+
+int execv(const char *path, char *const *argv)
+{
+ return execve(path, argv, environ);
+}
diff --git a/usr/klibc/execvp.c b/usr/klibc/execvp.c
new file mode 100644
index 0000000..7d8e2bc
--- /dev/null
+++ b/usr/klibc/execvp.c
@@ -0,0 +1,10 @@
+/*
+ * execvp.c
+ */
+
+#include <unistd.h>
+
+int execvp(const char *path, char *const *argv)
+{
+ return execvpe(path, argv, environ);
+}
diff --git a/usr/klibc/execvpe.c b/usr/klibc/execvpe.c
new file mode 100644
index 0000000..0b844f2
--- /dev/null
+++ b/usr/klibc/execvpe.c
@@ -0,0 +1,75 @@
+/*
+ * execvpe.c
+ *
+ * execvpe() function (from which we build execlp, execlpe, execvp).
+ *
+ * This version of execvpe() will *not* spawn /bin/sh if the command
+ * return ENOEXEC. That's what #! is for, folks!
+ *
+ * Since execlpe() and execvpe() aren't in POSIX, nor in glibc,
+ * I have followed QNX precedent in the implementation of the PATH:
+ * the PATH that is used is the one in the current environment, not
+ * in the new environment. Otherwise it would be impossible to pass
+ * a different PATH to the new process than the one one would want to
+ * use to search.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#define DEFAULT_PATH "/bin:/usr/bin:."
+
+int execvpe(const char *file, char *const *argv, char *const *envp)
+{
+ char path[PATH_MAX];
+ const char *searchpath, *esp;
+ size_t prefixlen, filelen, totallen;
+
+ if (strchr(file, '/')) /* Specific path */
+ return execve(file, argv, envp);
+
+ filelen = strlen(file);
+
+ searchpath = getenv("PATH");
+ if (!searchpath)
+ searchpath = DEFAULT_PATH;
+
+ errno = ENOENT; /* Default errno, if execve() doesn't
+ change it */
+
+ do {
+ esp = strchr(searchpath, ':');
+ if (esp)
+ prefixlen = esp - searchpath;
+ else
+ prefixlen = strlen(searchpath);
+
+ if (prefixlen == 0 || searchpath[prefixlen - 1] == '/') {
+ totallen = prefixlen + filelen;
+ if (totallen >= PATH_MAX)
+ continue;
+ memcpy(path, searchpath, prefixlen);
+ memcpy(path + prefixlen, file, filelen);
+ } else {
+ totallen = prefixlen + filelen + 1;
+ if (totallen >= PATH_MAX)
+ continue;
+ memcpy(path, searchpath, prefixlen);
+ path[prefixlen] = '/';
+ memcpy(path + prefixlen + 1, file, filelen);
+ }
+ path[totallen] = '\0';
+
+ execve(path, argv, envp);
+ if (errno == E2BIG || errno == ENOEXEC ||
+ errno == ENOMEM || errno == ETXTBSY)
+ break; /* Report this as an error, no more search */
+
+ searchpath = esp + 1;
+ } while (esp);
+
+ return -1;
+}
diff --git a/usr/klibc/exit.c b/usr/klibc/exit.c
new file mode 100644
index 0000000..2368b07
--- /dev/null
+++ b/usr/klibc/exit.c
@@ -0,0 +1,32 @@
+/*
+ * exit.c
+ *
+ * exit(), including the handling of the atexit chain.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include "atexit.h"
+
+/* Link chain for atexit/on_exit */
+struct atexit *__atexit_list;
+
+__noreturn exit(int rv)
+{
+ struct atexit *ap;
+
+ for (ap = __atexit_list; ap; ap = ap->next) {
+ /* This assumes extra args are harmless. They should
+ be in all normal C ABIs, but if an architecture has
+ some particularly bizarre ABI this might be worth
+ watching out for. */
+ ap->fctn(rv, ap->arg);
+ }
+
+ /* Handle any library destructors if we ever start using them... */
+ fflush(NULL);
+
+ _exit(rv);
+}
diff --git a/usr/klibc/fgets.c b/usr/klibc/fgets.c
new file mode 100644
index 0000000..b6e6f3e
--- /dev/null
+++ b/usr/klibc/fgets.c
@@ -0,0 +1,28 @@
+/*
+ * fgets.c
+ */
+
+#include <stdio.h>
+
+char *fgets(char *s, int n, FILE *f)
+{
+ int ch;
+ char *p = s;
+
+ while (n > 1) {
+ ch = getc(f);
+ if (ch == EOF) {
+ s = NULL;
+ break;
+ }
+ *p++ = ch;
+ n--;
+ if (ch == '\n')
+ break;
+ }
+ if (n)
+ *p = '\0';
+
+ return s;
+}
+__ALIAS(char *, fgets_unlocked, (char *, int, FILE *), fgets)
diff --git a/usr/klibc/fnmatch.c b/usr/klibc/fnmatch.c
new file mode 100644
index 0000000..5d0a25f
--- /dev/null
+++ b/usr/klibc/fnmatch.c
@@ -0,0 +1,72 @@
+/*
+ * fnmatch.c
+ *
+ * Original implementation by Kay Sievers, modified by H. Peter Anvin.
+ */
+
+#include <fnmatch.h>
+
+int fnmatch(const char *p, const char *s, int flags)
+{
+ if (flags & FNM_PATHNAME && *s == '/')
+ return (*p != '/') || fnmatch(p+1, s+1, flags);
+ if (flags & FNM_PERIOD && *s == '.')
+ return (*p != '.') || fnmatch(p+1, s+1, flags);
+
+ flags &= ~FNM_PERIOD; /* Only applies at beginning */
+
+ if (!(flags & FNM_NOESCAPE) && *p == '\\') {
+ p++;
+ return (*p != *s) || fnmatch(p+1, s+1, flags);
+ }
+
+ if (*s == '\0') {
+ while (*p == '*')
+ p++;
+ return (*p != '\0');
+ }
+
+ switch (*p) {
+ case '[':
+ {
+ int not = 0;
+ p++;
+ if (*p == '!') {
+ not = 1;
+ p++;
+ }
+ while ((*p != '\0') && (*p != ']')) {
+ int match = 0;
+ if (p[1] == '-') {
+ if ((*s >= *p) && (*s <= p[2]))
+ match = 1;
+ p += 3;
+ } else {
+ match = (*p == *s);
+ p++;
+ }
+ if (match ^ not) {
+ while ((*p != '\0') && (*p != ']'))
+ p++;
+ if (*p == ']')
+ return fnmatch(p+1, s+1, flags);
+ }
+ }
+ }
+ break;
+ case '*':
+ if (fnmatch(p, s+1, flags))
+ return fnmatch(p+1, s, flags);
+ return 0;
+ case '\0':
+ if (*s == '\0') {
+ return 0;
+ }
+ break;
+ default:
+ if ((*p == *s) || (*p == '?'))
+ return fnmatch(p+1, s+1, flags);
+ break;
+ }
+ return 1;
+}
diff --git a/usr/klibc/fork.c b/usr/klibc/fork.c
new file mode 100644
index 0000000..b07486e
--- /dev/null
+++ b/usr/klibc/fork.c
@@ -0,0 +1,21 @@
+/*
+ * fork.c
+ *
+ * This is normally just a syscall stub, but at least one system
+ * doesn't have sys_fork, only sys_clone...
+ */
+
+#include <sys/syscall.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sched.h>
+#include <klibc/sysconfig.h>
+
+#if !_KLIBC_NO_MMU && !defined(__NR_fork)
+
+pid_t fork(void)
+{
+ return __clone(SIGCHLD, 0);
+}
+
+#endif /* __NR_fork */
diff --git a/usr/klibc/fprintf.c b/usr/klibc/fprintf.c
new file mode 100644
index 0000000..8403923
--- /dev/null
+++ b/usr/klibc/fprintf.c
@@ -0,0 +1,19 @@
+/*
+ * fprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 16384
+
+int fprintf(FILE * file, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vfprintf(file, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/usr/klibc/fputc.c b/usr/klibc/fputc.c
new file mode 100644
index 0000000..7385d6f
--- /dev/null
+++ b/usr/klibc/fputc.c
@@ -0,0 +1,15 @@
+/*
+ * fputc.c
+ *
+ * gcc "printf decompilation" expects this to exist...
+ */
+
+#include <stdio.h>
+
+int fputc(int c, FILE *f)
+{
+ unsigned char ch = c;
+
+ return _fwrite(&ch, 1, f) == 1 ? ch : EOF;
+}
+__ALIAS(int, fputc_unlocked, (int, FILE *), fputc)
diff --git a/usr/klibc/fputs.c b/usr/klibc/fputs.c
new file mode 100644
index 0000000..cbc2056
--- /dev/null
+++ b/usr/klibc/fputs.c
@@ -0,0 +1,16 @@
+/*
+ * fputs.c
+ *
+ * This isn't quite fputs() in the stdio sense, since we don't
+ * have stdio, but it takes a file descriptor argument instead
+ * of the FILE *.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int fputs(const char *s, FILE *file)
+{
+ return _fwrite(s, strlen(s), file);
+}
+__ALIAS(int, fputs_unlocked, (const char *, FILE *), fputs)
diff --git a/usr/klibc/fread2.c b/usr/klibc/fread2.c
new file mode 100644
index 0000000..f5b2acb
--- /dev/null
+++ b/usr/klibc/fread2.c
@@ -0,0 +1,14 @@
+/*
+ * fread2.c
+ *
+ * The actual fread() function as a non-inline
+ */
+
+#define __NO_STDIO_INLINES
+#include <stdio.h>
+
+size_t fread(void *ptr, size_t size, size_t nmemb, FILE * f)
+{
+ return _fread(ptr, size * nmemb, f) / size;
+}
+__ALIAS(size_t, fread_unlocked, (void *, size_t, size_t, FILE *), fread)
diff --git a/usr/klibc/fstat.c b/usr/klibc/fstat.c
new file mode 100644
index 0000000..36dd661
--- /dev/null
+++ b/usr/klibc/fstat.c
@@ -0,0 +1,10 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+int fstat(int fd, struct stat *buf)
+{
+ return fstatat(fd, "", buf, AT_EMPTY_PATH);
+}
diff --git a/usr/klibc/fstatat.c b/usr/klibc/fstatat.c
new file mode 100644
index 0000000..12b5093
--- /dev/null
+++ b/usr/klibc/fstatat.c
@@ -0,0 +1,36 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+static void timespec_from_statx(struct timespec *ts,
+ const struct statx_timestamp *xts)
+{
+ ts->tv_sec = xts->tv_sec;
+ ts->tv_nsec = xts->tv_nsec;
+}
+
+int fstatat(int dirfd, const char *path, struct stat *buf, int flags)
+{
+ struct statx xbuf;
+
+ if (statx(dirfd, path, flags | AT_NO_AUTOMOUNT, STATX_BASIC_STATS,
+ &xbuf))
+ return -1;
+
+ buf->st_dev = makedev(xbuf.stx_dev_major, xbuf.stx_dev_minor);
+ buf->st_ino = xbuf.stx_ino;
+ buf->st_nlink = xbuf.stx_nlink;
+ buf->st_mode = xbuf.stx_mode;
+ buf->st_uid = xbuf.stx_uid;
+ buf->st_gid = xbuf.stx_gid;
+ buf->st_rdev = makedev(xbuf.stx_rdev_major, xbuf.stx_rdev_minor);
+ buf->st_size = xbuf.stx_size;
+ buf->st_blksize = xbuf.stx_blksize;
+ buf->st_blocks = xbuf.stx_blocks;
+ timespec_from_statx(&buf->st_atim, &xbuf.stx_atime);
+ timespec_from_statx(&buf->st_ctim, &xbuf.stx_ctime);
+ timespec_from_statx(&buf->st_mtim, &xbuf.stx_mtime);
+ return 0;
+}
diff --git a/usr/klibc/fstatfs.c b/usr/klibc/fstatfs.c
new file mode 100644
index 0000000..614f2ec
--- /dev/null
+++ b/usr/klibc/fstatfs.c
@@ -0,0 +1,19 @@
+/*
+ * fstatfs.c
+ *
+ * On architectures which do fstatfs64, wrap the system call
+ */
+
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+
+#ifdef __NR_fstatfs64
+
+extern int __fstatfs64(int, size_t, struct statfs *);
+
+int fstatfs(int fd, struct statfs *buf)
+{
+ return __fstatfs64(fd, sizeof *buf, buf);
+}
+
+#endif
diff --git a/usr/klibc/futimesat.c b/usr/klibc/futimesat.c
new file mode 100644
index 0000000..f4da4ba
--- /dev/null
+++ b/usr/klibc/futimesat.c
@@ -0,0 +1,18 @@
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+int futimesat(int dirfd, const char *filename, const struct timeval tvp[2])
+{
+ struct timespec ts[2];
+
+ if (tvp) {
+ ts[0].tv_sec = tvp[0].tv_sec;
+ ts[0].tv_nsec = tvp[0].tv_usec * 1000;
+ ts[1].tv_sec = tvp[1].tv_sec;
+ ts[1].tv_nsec = tvp[1].tv_usec * 1000;
+ }
+
+ return utimensat(dirfd, filename, &ts[0], 0);
+}
diff --git a/usr/klibc/fwrite2.c b/usr/klibc/fwrite2.c
new file mode 100644
index 0000000..a8c14c9
--- /dev/null
+++ b/usr/klibc/fwrite2.c
@@ -0,0 +1,15 @@
+/*
+ * fwrite2.c
+ *
+ * The actual fwrite() function as a non-inline
+ */
+
+#define __NO_STDIO_INLINES
+#include <stdio.h>
+
+size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE * f)
+{
+ return _fwrite(ptr, size * nmemb, f) / size;
+}
+__ALIAS(size_t, fwrite_unlocked, (const void *, size_t, size_t, FILE *),
+ fwrite)
diff --git a/usr/klibc/getcwd.c b/usr/klibc/getcwd.c
new file mode 100644
index 0000000..22ec812
--- /dev/null
+++ b/usr/klibc/getcwd.c
@@ -0,0 +1,15 @@
+/*
+ * getcwd.c
+ *
+ * The system call behaves differently than the library function.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+extern int __getcwd(char *buf, size_t size);
+
+char *getcwd(char *buf, size_t size)
+{
+ return (__getcwd(buf, size) < 0) ? NULL : buf;
+}
diff --git a/usr/klibc/getdomainname.c b/usr/klibc/getdomainname.c
new file mode 100644
index 0000000..218ff0b
--- /dev/null
+++ b/usr/klibc/getdomainname.c
@@ -0,0 +1,25 @@
+/*
+ * getdomainname.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int getdomainname(char *name, size_t len)
+{
+ struct utsname un;
+
+ if (uname(&un))
+ return -1;
+
+ if (len < strlen(un.domainname) + 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strcpy(name, un.domainname);
+
+ return 0;
+}
diff --git a/usr/klibc/getenv.c b/usr/klibc/getenv.c
new file mode 100644
index 0000000..3a4ae5e
--- /dev/null
+++ b/usr/klibc/getenv.c
@@ -0,0 +1,24 @@
+/*
+ * getenv.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *getenv(const char *name)
+{
+ char **p, *q;
+ int len = strlen(name);
+
+ if (!environ)
+ return NULL;
+
+ for (p = environ; (q = *p); p++) {
+ if (!strncmp(name, q, len) && q[len] == '=') {
+ return q + (len + 1);
+ }
+ }
+
+ return NULL;
+}
diff --git a/usr/klibc/gethostname.c b/usr/klibc/gethostname.c
new file mode 100644
index 0000000..120edd9
--- /dev/null
+++ b/usr/klibc/gethostname.c
@@ -0,0 +1,25 @@
+/*
+ * gethostname.c
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+int gethostname(char *name, size_t len)
+{
+ struct utsname un;
+
+ if (uname(&un))
+ return -1;
+
+ if (len < strlen(un.nodename) + 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ strcpy(name, un.nodename);
+
+ return 0;
+}
diff --git a/usr/klibc/getmntent.c b/usr/klibc/getmntent.c
new file mode 100644
index 0000000..8af27f3
--- /dev/null
+++ b/usr/klibc/getmntent.c
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mntent.h>
+
+#define BUFLEN 1024
+
+struct mntent *getmntent_r(FILE *fp, struct mntent *mntbuf, char *buf,
+ int buflen)
+{
+ char *line = NULL, *saveptr = NULL;
+ const char *sep = " \t\n";
+
+ if (!fp || !mntbuf || !buf)
+ return NULL;
+
+ while ((line = fgets(buf, buflen, fp)) != NULL) {
+ if (buf[0] == '#' || buf[0] == '\n')
+ continue;
+ break;
+ }
+
+ if (!line)
+ return NULL;
+
+ mntbuf->mnt_fsname = strtok_r(buf, sep, &saveptr);
+ if (!mntbuf->mnt_fsname)
+ return NULL;
+
+ mntbuf->mnt_dir = strtok_r(NULL, sep, &saveptr);
+ if (!mntbuf->mnt_fsname)
+ return NULL;
+
+ mntbuf->mnt_type = strtok_r(NULL, sep, &saveptr);
+ if (!mntbuf->mnt_type)
+ return NULL;
+
+ mntbuf->mnt_opts = strtok_r(NULL, sep, &saveptr);
+ if (!mntbuf->mnt_opts)
+ mntbuf->mnt_opts = "";
+
+ line = strtok_r(NULL, sep, &saveptr);
+ mntbuf->mnt_freq = !line ? 0 : atoi(line);
+
+ line = strtok_r(NULL, sep, &saveptr);
+ mntbuf->mnt_passno = !line ? 0 : atoi(line);
+
+ return mntbuf;
+}
+
+struct mntent *getmntent(FILE *fp)
+{
+ static char *buf = NULL;
+ static struct mntent mntbuf;
+
+ buf = malloc(BUFLEN);
+ if (!buf)
+ perror("malloc");
+
+ return getmntent_r(fp, &mntbuf, buf, BUFLEN);
+}
diff --git a/usr/klibc/getopt.c b/usr/klibc/getopt.c
new file mode 100644
index 0000000..806735d
--- /dev/null
+++ b/usr/klibc/getopt.c
@@ -0,0 +1,97 @@
+/*
+ * getopt.c
+ *
+ * Simple POSIX getopt(), no GNU extensions...
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+ const char *optptr;
+ const char *last_optstring;
+ char *const *last_argv;
+} pvt;
+
+int getopt(int argc, char *const *argv, const char *optstring)
+{
+ const char *carg;
+ const char *osptr;
+ int opt;
+
+ /* getopt() relies on a number of different global state
+ variables, which can make this really confusing if there is
+ more than one use of getopt() in the same program. This
+ attempts to detect that situation by detecting if the
+ "optstring" or "argv" argument have changed since last time
+ we were called; if so, reinitialize the query state. */
+
+ if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+ optind < 1 || optind > argc) {
+ /* optind doesn't match the current query */
+ pvt.last_optstring = optstring;
+ pvt.last_argv = argv;
+ optind = 1;
+ pvt.optptr = NULL;
+ }
+
+ carg = argv[optind];
+
+ /* First, eliminate all non-option cases */
+
+ if (!carg || carg[0] != '-' || !carg[1]) {
+ return -1;
+ }
+
+ if (carg[1] == '-' && !carg[2]) {
+ optind++;
+ return -1;
+ }
+
+ if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+ /* Someone frobbed optind, change to new opt. */
+ pvt.optptr = carg + 1;
+ }
+
+ opt = *pvt.optptr++;
+
+ if (opt != ':' && (osptr = strchr(optstring, opt))) {
+ if (osptr[1] == ':') {
+ if (*pvt.optptr) {
+ /* Argument-taking option with attached
+ argument */
+ optarg = (char *)pvt.optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached
+ argument */
+ if (argv[optind + 1]) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ optind++;
+ return (optstring[0] == ':')
+ ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* pvt.optptr will remember the exact position to
+ resume at */
+ if (!*pvt.optptr)
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if (!*pvt.optptr)
+ optind++;
+ return '?';
+ }
+}
diff --git a/usr/klibc/getopt_long.c b/usr/klibc/getopt_long.c
new file mode 100644
index 0000000..e3d064b
--- /dev/null
+++ b/usr/klibc/getopt_long.c
@@ -0,0 +1,152 @@
+/*
+ * getopt.c
+ *
+ * getopt_long(), or at least a common subset thereof:
+ *
+ * - Option reordering is not supported
+ * - -W foo is not supported
+ * - First optstring character "-" not supported.
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+ const char *optptr;
+ const char *last_optstring;
+ char *const *last_argv;
+} pvt;
+
+static inline const char *option_matches(const char *arg_str,
+ const char *opt_name)
+{
+ while (*arg_str != '\0' && *arg_str != '=') {
+ if (*arg_str++ != *opt_name++)
+ return NULL;
+ }
+
+ if (*opt_name)
+ return NULL;
+
+ return arg_str;
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longindex)
+{
+ const char *carg;
+ const char *osptr;
+ int opt;
+
+ /* getopt() relies on a number of different global state
+ variables, which can make this really confusing if there is
+ more than one use of getopt() in the same program. This
+ attempts to detect that situation by detecting if the
+ "optstring" or "argv" argument have changed since last time
+ we were called; if so, reinitialize the query state. */
+
+ if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+ optind < 1 || optind > argc) {
+ /* optind doesn't match the current query */
+ pvt.last_optstring = optstring;
+ pvt.last_argv = argv;
+ optind = 1;
+ pvt.optptr = NULL;
+ }
+
+ carg = argv[optind];
+
+ /* First, eliminate all non-option cases */
+
+ if (!carg || carg[0] != '-' || !carg[1])
+ return -1;
+
+ if (carg[1] == '-') {
+ const struct option *lo;
+ const char *opt_end = NULL;
+
+ optind++;
+
+ /* Either it's a long option, or it's -- */
+ if (!carg[2]) {
+ /* It's -- */
+ return -1;
+ }
+
+ for (lo = longopts; lo->name; lo++) {
+ if ((opt_end = option_matches(carg+2, lo->name)))
+ break;
+ }
+ if (!opt_end)
+ return '?';
+
+ if (longindex)
+ *longindex = lo-longopts;
+
+ if (*opt_end == '=') {
+ if (lo->has_arg)
+ optarg = (char *)opt_end+1;
+ else
+ return '?';
+ } else if (lo->has_arg == 1) {
+ if (!(optarg = argv[optind]))
+ return '?';
+ optind++;
+ }
+
+ if (lo->flag) {
+ *lo->flag = lo->val;
+ return 0;
+ } else {
+ return lo->val;
+ }
+ }
+
+ if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+ /* Someone frobbed optind, change to new opt. */
+ pvt.optptr = carg + 1;
+ }
+
+ opt = *pvt.optptr++;
+
+ if (opt != ':' && (osptr = strchr(optstring, opt))) {
+ if (osptr[1] == ':') {
+ if (*pvt.optptr) {
+ /* Argument-taking option with attached
+ argument */
+ optarg = (char *)pvt.optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached
+ argument */
+ if (argv[optind + 1]) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ optind++;
+ return (optstring[0] == ':')
+ ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* pvt.optptr will remember the exact position to
+ resume at */
+ if (!*pvt.optptr)
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if (!*pvt.optptr)
+ optind++;
+ return '?';
+ }
+}
diff --git a/usr/klibc/getpgrp.c b/usr/klibc/getpgrp.c
new file mode 100644
index 0000000..b20b17a
--- /dev/null
+++ b/usr/klibc/getpgrp.c
@@ -0,0 +1,10 @@
+/*
+ * getpgrp.c
+ */
+
+#include <unistd.h>
+
+pid_t getpgrp(void)
+{
+ return getpgid(0);
+}
diff --git a/usr/klibc/getpriority.c b/usr/klibc/getpriority.c
new file mode 100644
index 0000000..01d6e06
--- /dev/null
+++ b/usr/klibc/getpriority.c
@@ -0,0 +1,23 @@
+/*
+ * getpriority.c
+ *
+ * Needs to do some post-syscall mangling to distinguish error returns...
+ * but only on some platforms. Sigh.
+ */
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#if !defined(__alpha__) && !defined(__ia64__)
+
+extern int __getpriority(int, int);
+
+int getpriority(int which, int who)
+{
+ int rv = __getpriority(which, who);
+ return (rv < 0) ? rv : 20-rv;
+}
+
+#endif
diff --git a/usr/klibc/gettimeofday.c b/usr/klibc/gettimeofday.c
new file mode 100644
index 0000000..919c46d
--- /dev/null
+++ b/usr/klibc/gettimeofday.c
@@ -0,0 +1,22 @@
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+extern int __gettimeofday(void *, struct timezone *);
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct timespec ts;
+
+ if (tv) {
+ if (clock_gettime(CLOCK_REALTIME, &ts))
+ return -1;
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+
+ if (tz && __gettimeofday(NULL, tz))
+ return -1;
+
+ return 0;
+}
diff --git a/usr/klibc/globals.c b/usr/klibc/globals.c
new file mode 100644
index 0000000..72ae91f
--- /dev/null
+++ b/usr/klibc/globals.c
@@ -0,0 +1,10 @@
+/*
+ * globals.c
+ *
+ * These have to be defined somewhere...
+ */
+#include <errno.h>
+#include <unistd.h>
+
+int errno;
+char **environ;
diff --git a/usr/klibc/inet/bindresvport.c b/usr/klibc/inet/bindresvport.c
new file mode 100644
index 0000000..e22c1c2
--- /dev/null
+++ b/usr/klibc/inet/bindresvport.c
@@ -0,0 +1,46 @@
+/*
+ * inet/bindresvport.c
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+#define START_PORT 768
+#define END_PORT IPPORT_RESERVED
+#define NUM_PORTS (END_PORT - START_PORT)
+
+int bindresvport(int sd, struct sockaddr_in *sin)
+{
+ struct sockaddr_in me;
+ static short port;
+ int ret = 0;
+ int i;
+
+ if (sin == NULL) {
+ memset(&me, 0, sizeof(me));
+ sin = &me;
+ sin->sin_family = AF_INET;
+ } else if (sin->sin_family != AF_INET) {
+ errno = EPFNOSUPPORT;
+ return -1;
+ }
+
+ if (port == 0)
+ port = START_PORT + (getpid() % NUM_PORTS);
+
+ for (i = 0; i < NUM_PORTS; i++, port++) {
+ if (port == END_PORT)
+ port = START_PORT;
+ sin->sin_port = htons(port);
+
+ ret = bind(sd, (struct sockaddr *)sin, sizeof(*sin));
+ if (ret != -1)
+ break;
+ }
+
+ return ret;
+}
diff --git a/usr/klibc/inet/inet_addr.c b/usr/klibc/inet/inet_addr.c
new file mode 100644
index 0000000..ba086c3
--- /dev/null
+++ b/usr/klibc/inet/inet_addr.c
@@ -0,0 +1,14 @@
+/*
+ * inet/inet_addr.c
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+uint32_t inet_addr(const char *str)
+{
+ struct in_addr a;
+ int rv = inet_aton(str, &a);
+
+ return rv ? a.s_addr : INADDR_NONE;
+}
diff --git a/usr/klibc/inet/inet_aton.c b/usr/klibc/inet/inet_aton.c
new file mode 100644
index 0000000..beceeea
--- /dev/null
+++ b/usr/klibc/inet/inet_aton.c
@@ -0,0 +1,22 @@
+/*
+ * inet/inet_aton.c
+ */
+
+#include <arpa/inet.h>
+#include <stdio.h>
+
+int inet_aton(const char *str, struct in_addr *addr)
+{
+ union {
+ uint8_t b[4];
+ uint32_t l;
+ } a;
+
+ if (sscanf(str, "%hhu.%hhu.%hhu.%hhu",
+ &a.b[0], &a.b[1], &a.b[2], &a.b[3]) == 4) {
+ addr->s_addr = a.l; /* Always in network byte order */
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/usr/klibc/inet/inet_ntoa.c b/usr/klibc/inet/inet_ntoa.c
new file mode 100644
index 0000000..6dbf057
--- /dev/null
+++ b/usr/klibc/inet/inet_ntoa.c
@@ -0,0 +1,16 @@
+/*
+ * inet/inet_ntoa.c
+ */
+
+#include <stdint.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+char *inet_ntoa(struct in_addr addr)
+{
+ static char name[16];
+ const uint8_t *cp = (const uint8_t *) &addr.s_addr;
+
+ sprintf(name, "%u.%u.%u.%u", cp[0], cp[1], cp[2], cp[3]);
+ return name;
+}
diff --git a/usr/klibc/inet/inet_ntop.c b/usr/klibc/inet/inet_ntop.c
new file mode 100644
index 0000000..106fb45
--- /dev/null
+++ b/usr/klibc/inet/inet_ntop.c
@@ -0,0 +1,54 @@
+/*
+ * inet/inet_ntop.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in6.h>
+
+const char *inet_ntop(int af, const void *cp, char *buf, size_t len)
+{
+ size_t xlen;
+
+ switch (af) {
+ case AF_INET:
+ {
+ const uint8_t *bp = (const uint8_t *)
+ &((const struct in_addr *)cp)->s_addr;
+
+ xlen = snprintf(buf, len, "%u.%u.%u.%u",
+ bp[0], bp[1], bp[2], bp[3]);
+ }
+ break;
+
+ case AF_INET6:
+ {
+ const struct in6_addr *s = (const struct in6_addr *)cp;
+
+ xlen = snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(s->s6_addr16[0]),
+ ntohs(s->s6_addr16[1]),
+ ntohs(s->s6_addr16[2]),
+ ntohs(s->s6_addr16[3]),
+ ntohs(s->s6_addr16[4]),
+ ntohs(s->s6_addr16[5]),
+ ntohs(s->s6_addr16[6]),
+ ntohs(s->s6_addr16[7]));
+ }
+ break;
+
+ default:
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+
+ if (xlen > len) {
+ errno = ENOSPC;
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/usr/klibc/inet/inet_pton.c b/usr/klibc/inet/inet_pton.c
new file mode 100644
index 0000000..19fe16e
--- /dev/null
+++ b/usr/klibc/inet/inet_pton.c
@@ -0,0 +1,78 @@
+/*
+ * inet/inet_pton.c
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in6.h>
+
+static inline int hexval(int ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'A' && ch <= 'F') {
+ return ch - 'A' + 10;
+ } else if (ch >= 'a' && ch <= 'f') {
+ return ch - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+int inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return inet_aton(src, (struct in_addr *)dst);
+
+ case AF_INET6:
+ {
+ struct in6_addr *d = (struct in6_addr *)dst;
+ int colons = 0, dcolons = 0;
+ int i;
+ const char *p;
+
+ /* A double colon will increment colons by 2,
+ dcolons by 1 */
+ for (p = dst; *p; p++) {
+ if (p[0] == ':') {
+ colons++;
+ if (p[1] == ':')
+ dcolons++;
+ } else if (!isxdigit(*p))
+ return 0; /* Invalid address */
+ }
+
+ if (colons > 7 || dcolons > 1
+ || (!dcolons && colons != 7))
+ return 0; /* Invalid address */
+
+ memset(d, 0, sizeof(struct in6_addr));
+
+ i = 0;
+ for (p = dst; *p; p++) {
+ if (*p == ':') {
+ if (p[1] == ':') {
+ i += (8 - colons);
+ } else {
+ i++;
+ }
+ } else {
+ d->s6_addr16[i] =
+ htons((ntohs(d->s6_addr16[i]) << 4)
+ + hexval(*p));
+ }
+ }
+
+ return 1;
+ }
+
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
diff --git a/usr/klibc/isatty.c b/usr/klibc/isatty.c
new file mode 100644
index 0000000..2359479
--- /dev/null
+++ b/usr/klibc/isatty.c
@@ -0,0 +1,16 @@
+/*
+ * isatty.c
+ */
+
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+
+int isatty(int fd)
+{
+ struct termios dummy;
+
+ /* All ttys support TIOCGPGRP */
+ /* except /dev/console which needs TCGETS */
+ return !ioctl(fd, TCGETS, &dummy);
+}
diff --git a/usr/klibc/jrand48.c b/usr/klibc/jrand48.c
new file mode 100644
index 0000000..8e2b3ac
--- /dev/null
+++ b/usr/klibc/jrand48.c
@@ -0,0 +1,24 @@
+/*
+ * jrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+long jrand48(unsigned short xsubi[3])
+{
+ uint64_t x;
+
+ /* The xsubi[] array is littleendian by spec */
+ x = (uint64_t) (uint16_t) xsubi[0] +
+ ((uint64_t) (uint16_t) xsubi[1] << 16) +
+ ((uint64_t) (uint16_t) xsubi[2] << 32);
+
+ x = (0x5deece66dULL * x) + 0xb;
+
+ xsubi[0] = (unsigned short)(uint16_t) x;
+ xsubi[1] = (unsigned short)(uint16_t) (x >> 16);
+ xsubi[2] = (unsigned short)(uint16_t) (x >> 32);
+
+ return (long)(int32_t) (x >> 16);
+}
diff --git a/usr/klibc/lchown.c b/usr/klibc/lchown.c
new file mode 100644
index 0000000..9a9e1e1
--- /dev/null
+++ b/usr/klibc/lchown.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_lchown
+
+int lchown(const char *path, uid_t owner, gid_t group)
+{
+ return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW);
+}
+
+#endif /* __NR_lchown */
diff --git a/usr/klibc/libc_init.c b/usr/klibc/libc_init.c
new file mode 100644
index 0000000..c5b9bab
--- /dev/null
+++ b/usr/klibc/libc_init.c
@@ -0,0 +1,121 @@
+/*
+ * libc_init.c
+ *
+ * This function takes the raw data block set up by the ELF loader
+ * in the kernel and parses it. It is invoked by crt0.S which makes
+ * any necessary adjustments and passes calls this function using
+ * the standard C calling convention.
+ *
+ * The arguments are:
+ * uintptr_t *elfdata -- The ELF loader data block; usually from the stack.
+ * Basically a pointer to argc.
+ * void (*onexit)(void) -- Function to install into onexit
+ */
+
+/*
+ * Several Linux ABIs don't pass the onexit pointer, and the ones that
+ * do never use it. Therefore, unless USE_ONEXIT is defined, we just
+ * ignore the onexit pointer.
+ */
+/* #define USE_ONEXIT */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <klibc/compiler.h>
+#include <elf.h>
+#include <sys/auxv.h>
+#include <klibc/sysconfig.h>
+#include "atexit.h"
+
+#if _KLIBC_HAS_ARCHINIT
+# include "klibc/archinit.h"
+#else
+# define __libc_archinit() ((void)0)
+#endif
+
+/* This file is included from __static_init.c or __shared_init.c */
+#ifndef SHARED
+# error "SHARED should be defined to 0 or 1"
+#endif
+
+char **environ;
+unsigned int __page_size, __page_shift;
+
+struct auxentry {
+ unsigned long type;
+ unsigned long v;
+};
+
+extern void __libc_init_stdio(void);
+
+unsigned long __auxval[_AUXVAL_MAX];
+
+__noreturn __libc_init(uintptr_t * elfdata, void (*onexit) (void))
+{
+ int argc;
+ char **argv, **envp, **envend;
+ struct auxentry *auxentry;
+#if SHARED
+ typedef int (*main_t) (int, char **, char **);
+ main_t MAIN = NULL;
+#else
+ extern int main(int, char **, char **);
+#define MAIN main
+#endif
+ unsigned int page_size = 0, page_shift = 0;
+
+#ifdef USE_ONEXIT
+ if (onexit) {
+ static struct atexit at_exit;
+
+ at_exit.fctn = (void (*)(int, void *))onexit;
+ /* at_exit.next = NULL already */
+ __atexit_list = &at_exit;
+ }
+#else
+ (void)onexit; /* Ignore this... */
+#endif
+
+ argc = (int)*elfdata++;
+ argv = (char **)elfdata;
+ envp = argv + (argc + 1);
+
+ /* The auxillary entry vector is after all the environment vars */
+ for (envend = envp; *envend; envend++) ;
+ auxentry = (struct auxentry *)(envend + 1);
+
+ while (auxentry->type) {
+ if (auxentry->type < _AUXVAL_MAX)
+ __auxval[auxentry->type] = auxentry->v;
+ auxentry++;
+ }
+
+#if SHARED
+ MAIN = (main_t) __auxval[AT_ENTRY];
+#endif
+
+ __page_size = page_size = __auxval[AT_PAGESZ];
+
+#if __GNUC__ >= 4
+ /* unsigned int is 32 bits on all our architectures */
+ page_shift = __builtin_clz(page_size) ^ 31;
+#elif defined(__i386__) || defined(__x86_64__)
+ asm("bsrl %1,%0" : "=r" (page_shift) : "r" (page_size));
+#else
+ while (page_size > 1) {
+ page_shift++;
+ page_size >>= 1;
+ }
+#endif
+ __page_shift = page_shift;
+
+#if _KLIBC_HAS_ARCHINIT
+ __libc_archinit();
+#endif
+
+ __libc_init_stdio();
+
+ environ = envp;
+ exit(MAIN(argc, argv, envp));
+}
diff --git a/usr/klibc/libgcc/__ashldi3.c b/usr/klibc/libgcc/__ashldi3.c
new file mode 100644
index 0000000..95937f0
--- /dev/null
+++ b/usr/klibc/libgcc/__ashldi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__ashldi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __ashldi3(uint64_t v, int cnt)
+{
+ int c = cnt & 31;
+ uint32_t vl = (uint32_t) v;
+ uint32_t vh = (uint32_t) (v >> 32);
+
+ if (cnt & 32) {
+ vh = (vl << c);
+ vl = 0;
+ } else {
+ vh = (vh << c) + (vl >> (32 - c));
+ vl = (vl << c);
+ }
+
+ return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__ashrdi3.c b/usr/klibc/libgcc/__ashrdi3.c
new file mode 100644
index 0000000..14e6d18
--- /dev/null
+++ b/usr/klibc/libgcc/__ashrdi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__ashrdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __ashrdi3(uint64_t v, int cnt)
+{
+ int c = cnt & 31;
+ uint32_t vl = (uint32_t) v;
+ uint32_t vh = (uint32_t) (v >> 32);
+
+ if (cnt & 32) {
+ vl = ((int32_t) vh >> c);
+ vh = (int32_t) vh >> 31;
+ } else {
+ vl = (vl >> c) + (vh << (32 - c));
+ vh = ((int32_t) vh >> c);
+ }
+
+ return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__clzsi2.c b/usr/klibc/libgcc/__clzsi2.c
new file mode 100644
index 0000000..ebb11f0
--- /dev/null
+++ b/usr/klibc/libgcc/__clzsi2.c
@@ -0,0 +1,36 @@
+/*
+ * libgcc/__clzsi2.c
+ *
+ * Returns the leading number of 0 bits in the argument
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint32_t __clzsi2(uint32_t v)
+{
+ int p = 31;
+
+ if (v & 0xffff0000) {
+ p -= 16;
+ v >>= 16;
+ }
+ if (v & 0xff00) {
+ p -= 8;
+ v >>= 8;
+ }
+ if (v & 0xf0) {
+ p -= 4;
+ v >>= 4;
+ }
+ if (v & 0xc) {
+ p -= 2;
+ v >>= 2;
+ }
+ if (v & 0x2) {
+ p -= 1;
+ v >>= 1;
+ }
+
+ return p;
+}
diff --git a/usr/klibc/libgcc/__divdi3.c b/usr/klibc/libgcc/__divdi3.c
new file mode 100644
index 0000000..973fe63
--- /dev/null
+++ b/usr/klibc/libgcc/__divdi3.c
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+int64_t __divdi3(int64_t num, int64_t den)
+{
+ int minus = 0;
+ int64_t v;
+
+ if (num < 0) {
+ num = -num;
+ minus = 1;
+ }
+ if (den < 0) {
+ den = -den;
+ minus ^= 1;
+ }
+
+ v = __udivmoddi4(num, den, NULL);
+ if (minus)
+ v = -v;
+
+ return v;
+}
diff --git a/usr/klibc/libgcc/__divsi3.c b/usr/klibc/libgcc/__divsi3.c
new file mode 100644
index 0000000..35420f5
--- /dev/null
+++ b/usr/klibc/libgcc/__divsi3.c
@@ -0,0 +1,29 @@
+/*
+ * libgcc/__divsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+int32_t __divsi3(int32_t num, int32_t den)
+{
+ int minus = 0;
+ int32_t v;
+
+ if (num < 0) {
+ num = -num;
+ minus = 1;
+ }
+ if (den < 0) {
+ den = -den;
+ minus ^= 1;
+ }
+
+ v = __udivmodsi4(num, den, NULL);
+ if (minus)
+ v = -v;
+
+ return v;
+}
diff --git a/usr/klibc/libgcc/__lshrdi3.c b/usr/klibc/libgcc/__lshrdi3.c
new file mode 100644
index 0000000..765e1f2
--- /dev/null
+++ b/usr/klibc/libgcc/__lshrdi3.c
@@ -0,0 +1,23 @@
+/*
+ * libgcc/__lshrdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint64_t __lshrdi3(uint64_t v, int cnt)
+{
+ int c = cnt & 31;
+ uint32_t vl = (uint32_t) v;
+ uint32_t vh = (uint32_t) (v >> 32);
+
+ if (cnt & 32) {
+ vl = (vh >> c);
+ vh = 0;
+ } else {
+ vl = (vl >> c) + (vh << (32 - c));
+ vh = (vh >> c);
+ }
+
+ return ((uint64_t) vh << 32) + vl;
+}
diff --git a/usr/klibc/libgcc/__moddi3.c b/usr/klibc/libgcc/__moddi3.c
new file mode 100644
index 0000000..0e7ed98
--- /dev/null
+++ b/usr/klibc/libgcc/__moddi3.c
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__moddi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+int64_t __moddi3(int64_t num, int64_t den)
+{
+ int minus = 0;
+ int64_t v;
+
+ if (num < 0) {
+ num = -num;
+ minus = 1;
+ }
+ if (den < 0) {
+ den = -den;
+ minus ^= 1;
+ }
+
+ (void)__udivmoddi4(num, den, (uint64_t *) & v);
+ if (minus)
+ v = -v;
+
+ return v;
+}
diff --git a/usr/klibc/libgcc/__modsi3.c b/usr/klibc/libgcc/__modsi3.c
new file mode 100644
index 0000000..33a21ba
--- /dev/null
+++ b/usr/klibc/libgcc/__modsi3.c
@@ -0,0 +1,29 @@
+/*
+ * libgcc/__modsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+int32_t __modsi3(int32_t num, int32_t den)
+{
+ int minus = 0;
+ int32_t v;
+
+ if (num < 0) {
+ num = -num;
+ minus = 1;
+ }
+ if (den < 0) {
+ den = -den;
+ minus ^= 1;
+ }
+
+ (void)__udivmodsi4(num, den, (uint32_t *) & v);
+ if (minus)
+ v = -v;
+
+ return v;
+}
diff --git a/usr/klibc/libgcc/__udivdi3.c b/usr/klibc/libgcc/__udivdi3.c
new file mode 100644
index 0000000..5eea461
--- /dev/null
+++ b/usr/klibc/libgcc/__udivdi3.c
@@ -0,0 +1,13 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+uint64_t __udivdi3(uint64_t num, uint64_t den)
+{
+ return __udivmoddi4(num, den, NULL);
+}
diff --git a/usr/klibc/libgcc/__udivmoddi4.c b/usr/klibc/libgcc/__udivmoddi4.c
new file mode 100644
index 0000000..aa86112
--- /dev/null
+++ b/usr/klibc/libgcc/__udivmoddi4.c
@@ -0,0 +1,32 @@
+#include <klibc/diverr.h>
+#include <stdint.h>
+
+uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem_p)
+{
+ uint64_t quot = 0, qbit = 1;
+
+ if (den == 0) {
+ __divide_error();
+ return 0; /* If trap returns... */
+ }
+
+ /* Left-justify denominator and count shift */
+ while ((int64_t) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ if (rem_p)
+ *rem_p = num;
+
+ return quot;
+}
diff --git a/usr/klibc/libgcc/__udivmodsi4.c b/usr/klibc/libgcc/__udivmodsi4.c
new file mode 100644
index 0000000..54980f0
--- /dev/null
+++ b/usr/klibc/libgcc/__udivmodsi4.c
@@ -0,0 +1,32 @@
+#include <klibc/diverr.h>
+#include <stdint.h>
+
+uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem_p)
+{
+ uint32_t quot = 0, qbit = 1;
+
+ if (den == 0) {
+ __divide_error();
+ return 0; /* If trap returns... */
+ }
+
+ /* Left-justify denominator and count shift */
+ while ((int32_t) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ if (rem_p)
+ *rem_p = num;
+
+ return quot;
+}
diff --git a/usr/klibc/libgcc/__udivsi3.c b/usr/klibc/libgcc/__udivsi3.c
new file mode 100644
index 0000000..5635f3f
--- /dev/null
+++ b/usr/klibc/libgcc/__udivsi3.c
@@ -0,0 +1,13 @@
+/*
+ * libgcc/__divsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+uint32_t __udivsi3(uint32_t num, uint32_t den)
+{
+ return __udivmodsi4(num, den, NULL);
+}
diff --git a/usr/klibc/libgcc/__umoddi3.c b/usr/klibc/libgcc/__umoddi3.c
new file mode 100644
index 0000000..1fc754a
--- /dev/null
+++ b/usr/klibc/libgcc/__umoddi3.c
@@ -0,0 +1,16 @@
+/*
+ * arch/i386/libgcc/__umoddi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+uint64_t __umoddi3(uint64_t num, uint64_t den)
+{
+ uint64_t v;
+
+ (void)__udivmoddi4(num, den, &v);
+ return v;
+}
diff --git a/usr/klibc/libgcc/__umodsi3.c b/usr/klibc/libgcc/__umodsi3.c
new file mode 100644
index 0000000..85e6e3c
--- /dev/null
+++ b/usr/klibc/libgcc/__umodsi3.c
@@ -0,0 +1,16 @@
+/*
+ * libgcc/__umodsi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint32_t __udivmodsi4(uint32_t num, uint32_t den, uint32_t * rem);
+
+uint32_t __umodsi3(uint32_t num, uint32_t den)
+{
+ uint32_t v;
+
+ (void)__udivmodsi4(num, den, &v);
+ return v;
+}
diff --git a/usr/klibc/link.c b/usr/klibc/link.c
new file mode 100644
index 0000000..1d4b70e
--- /dev/null
+++ b/usr/klibc/link.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_link
+
+int link(const char *oldpath, const char *newpath)
+{
+ return linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
+}
+
+#endif /* __NR_link */
diff --git a/usr/klibc/lrand48.c b/usr/klibc/lrand48.c
new file mode 100644
index 0000000..7dfcf92
--- /dev/null
+++ b/usr/klibc/lrand48.c
@@ -0,0 +1,13 @@
+/*
+ * lrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3]; /* Common with mrand48.c, srand48.c */
+
+long lrand48(void)
+{
+ return (uint32_t) jrand48(__rand48_seed) >> 1;
+}
diff --git a/usr/klibc/lseek.c b/usr/klibc/lseek.c
new file mode 100644
index 0000000..f262d19
--- /dev/null
+++ b/usr/klibc/lseek.c
@@ -0,0 +1,31 @@
+/*
+ * lseek.c
+ *
+ * On 32-bit platforms, we need to use the _llseek() system call
+ * rather than lseek(), to be able to handle large disks. _llseek()
+ * isn't just a normal syscall which takes a 64-bit argument; it needs
+ * to return a 64-bit value and so takes an extra pointer.
+ */
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <bitsize.h>
+
+#if _BITSIZE == 32
+
+extern int __llseek(int fd, unsigned long hi, unsigned long lo, off_t * res,
+ int whence);
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+ unsigned long long ullo = offset;
+ off_t result;
+ int rv;
+
+ rv = __llseek(fd, (unsigned long)(ullo >> 32), (unsigned long)ullo,
+ &result, whence);
+
+ return rv ? (off_t)-1 : result;
+}
+
+#endif
diff --git a/usr/klibc/lstat.c b/usr/klibc/lstat.c
new file mode 100644
index 0000000..3e8146f
--- /dev/null
+++ b/usr/klibc/lstat.c
@@ -0,0 +1,10 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+int lstat(const char *path, struct stat *buf)
+{
+ return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+}
diff --git a/usr/klibc/makeerrlist.pl b/usr/klibc/makeerrlist.pl
new file mode 100644
index 0000000..43c747c
--- /dev/null
+++ b/usr/klibc/makeerrlist.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+#
+# This creates sys_errlist from <asm/errno.h> through somewhat
+# heuristic matching. It presumes the relevant entries are of the form
+# #define Exxxx <integer> /* comment */
+#
+
+use FileHandle;
+
+%errors = ();
+%errmsg = ();
+$maxerr = -1;
+@includelist = (); # Include directories
+
+sub parse_file($) {
+ my($file) = @_;
+ my($fh) = new FileHandle;
+ my($line, $error, $msg);
+ my($kernelonly) = 0;
+ my($root);
+
+ print STDERR "opening $file\n" unless ( $quiet );
+
+ $ok = 0;
+ foreach $root ( @includelist ) {
+ if ( $fh->open($root.'//'.$file, '<') ) {
+ $ok = 1;
+ last;
+ }
+ }
+
+ if ( ! $ok ) {
+ die "$0: Cannot find file $file\n";
+ }
+
+ while ( defined($line = <$fh>) ) {
+ if ( $kernelonly ) {
+ if ( $line =~ /^\#\s*endif/ ) {
+ $kernelonly--;
+ } elsif ( $line =~ /^\#\sif/ ) {
+ $kernelonly++;
+ }
+ } else {
+ if ( $line =~ /^\#\s*define\s+([A-Z0-9_]+)\s+([0-9]+)\s*\/\*\s*(.*\S)\s*\*\// ) {
+ $error = $1;
+ $errno = $2+0;
+ $msg = $3;
+ print STDERR "$error ($errno) => \"$msg\"\n" unless ( $quiet );
+ $errors{$errno} = $error;
+ $errmsg{$errno} = $msg;
+ $maxerr = $errno if ( $errno > $maxerr );
+ } elsif ( $line =~ /^\#\s*include\s+[\<\"](.*)[\>\"]/ ) {
+ parse_file($1);
+ } elsif ( $line =~ /^\#\s*ifdef\s+__KERNEL__/ ) {
+ $kernelonly++;
+ }
+ }
+ }
+ close($fh);
+ print STDERR "closing $file\n" unless ( $quiet );
+}
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) ? !$v : 0;
+
+foreach $arg ( @ARGV ) {
+ if ( $arg eq '-q' ) {
+ $quiet = 1;
+ } elsif ( $arg =~ /^-(errlist|errnos|maxerr)$/ ) {
+ $type = $arg;
+ } elsif ( $arg =~ '^\-I' ) {
+ push(@includelist, "$'");
+ } else {
+ # Ignore
+ }
+}
+
+parse_file('linux/errno.h');
+
+if ( $type eq '-errlist' ) {
+ print "#include <errno.h>\n";
+ printf "const int sys_nerr = %d;\n", $maxerr+1;
+ printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+ foreach $e ( sort(keys(%errors)) ) {
+ printf " [%s] = \"%s\",\n", $errors{$e}, $errmsg{$e};
+ }
+ print "};\n";
+} elsif ( $type eq '-errnos' ) {
+ print "#include <errno.h>\n";
+ printf "const int sys_nerr = %d;\n", $maxerr+1;
+ printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+ foreach $e ( sort(keys(%errors)) ) {
+ printf " [%s] = \"%s\",\n", $errors{$e}, $errors{$e};
+ }
+ print "};\n";
+} elsif ( $type eq '-maxerr' ) {
+ print $maxerr, "\n";
+}
diff --git a/usr/klibc/malloc.c b/usr/klibc/malloc.c
new file mode 100644
index 0000000..09a596f
--- /dev/null
+++ b/usr/klibc/malloc.c
@@ -0,0 +1,299 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <errno.h>
+#include "malloc.h"
+
+/* Both the arena list and the free memory list are double linked
+ list with head node. This the head node. Note that the arena list
+ is sorted in order of address. */
+static struct free_arena_header __malloc_head = {
+ {
+ ARENA_TYPE_HEAD,
+ 0,
+ &__malloc_head,
+ &__malloc_head,
+ },
+ &__malloc_head,
+ &__malloc_head
+};
+
+static inline void mark_block_dead(struct free_arena_header *ah)
+{
+#ifdef DEBUG_MALLOC
+ ah->a.type = ARENA_TYPE_DEAD;
+#endif
+}
+
+static inline void remove_from_main_chain(struct free_arena_header *ah)
+{
+ struct free_arena_header *ap, *an;
+
+ mark_block_dead(ah);
+
+ ap = ah->a.prev;
+ an = ah->a.next;
+ ap->a.next = an;
+ an->a.prev = ap;
+}
+
+static inline void remove_from_free_chain(struct free_arena_header *ah)
+{
+ struct free_arena_header *ap, *an;
+
+ ap = ah->prev_free;
+ an = ah->next_free;
+ ap->next_free = an;
+ an->prev_free = ap;
+}
+
+static inline void remove_from_chains(struct free_arena_header *ah)
+{
+ remove_from_free_chain(ah);
+ remove_from_main_chain(ah);
+}
+
+static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
+{
+ size_t fsize;
+ struct free_arena_header *nfp, *na, *fpn, *fpp;
+
+ fsize = fp->a.size;
+
+ /* We need the 2* to account for the larger requirements of a
+ free block */
+ if (fsize >= size + 2 * sizeof(struct arena_header)) {
+ /* Bigger block than required -- split block */
+ nfp = (struct free_arena_header *)((char *)fp + size);
+ na = fp->a.next;
+
+ nfp->a.type = ARENA_TYPE_FREE;
+ nfp->a.size = fsize - size;
+ fp->a.type = ARENA_TYPE_USED;
+ fp->a.size = size;
+
+ /* Insert into all-block chain */
+ nfp->a.prev = fp;
+ nfp->a.next = na;
+ na->a.prev = nfp;
+ fp->a.next = nfp;
+
+ /* Replace current block on free chain */
+ nfp->next_free = fpn = fp->next_free;
+ nfp->prev_free = fpp = fp->prev_free;
+ fpn->prev_free = nfp;
+ fpp->next_free = nfp;
+ } else {
+ fp->a.type = ARENA_TYPE_USED; /* Allocate the whole block */
+ remove_from_free_chain(fp);
+ }
+
+ return (void *)(&fp->a + 1);
+}
+
+static struct free_arena_header *__free_block(struct free_arena_header *ah)
+{
+ struct free_arena_header *pah, *nah;
+
+ pah = ah->a.prev;
+ nah = ah->a.next;
+ if (pah->a.type == ARENA_TYPE_FREE &&
+ (char *)pah + pah->a.size == (char *)ah) {
+ /* Coalesce into the previous block */
+ pah->a.size += ah->a.size;
+ pah->a.next = nah;
+ nah->a.prev = pah;
+ mark_block_dead(ah);
+
+ ah = pah;
+ pah = ah->a.prev;
+ } else {
+ /* Need to add this block to the free chain */
+ ah->a.type = ARENA_TYPE_FREE;
+
+ ah->next_free = __malloc_head.next_free;
+ ah->prev_free = &__malloc_head;
+ __malloc_head.next_free = ah;
+ ah->next_free->prev_free = ah;
+ }
+
+ /* In either of the previous cases, we might be able to merge
+ with the subsequent block... */
+ if (nah->a.type == ARENA_TYPE_FREE &&
+ (char *)ah + ah->a.size == (char *)nah) {
+ ah->a.size += nah->a.size;
+
+ /* Remove the old block from the chains */
+ remove_from_chains(nah);
+ }
+
+ /* Return the block that contains the called block */
+ return ah;
+}
+
+void *malloc(size_t size)
+{
+ struct free_arena_header *fp;
+ struct free_arena_header *pah;
+ size_t fsize;
+
+ if (size == 0)
+ return NULL;
+
+ /* Various additions below will overflow if size is close to
+ SIZE_MAX. Further, it's not legal for a C object to be
+ larger than PTRDIFF_MAX (half of SIZE_MAX) as pointer
+ arithmetic within it could overflow. */
+ if (size > PTRDIFF_MAX) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* Add the obligatory arena header, and round up */
+ size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
+
+ for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD;
+ fp = fp->next_free) {
+ if (fp->a.size >= size) {
+ /* Found fit -- allocate out of this block */
+ return __malloc_from_block(fp, size);
+ }
+ }
+
+ /* Nothing found... need to request a block from the kernel */
+ fsize = (size + MALLOC_CHUNK_MASK) & ~MALLOC_CHUNK_MASK;
+
+#if _KLIBC_MALLOC_USES_SBRK
+ if (fsize > INTPTR_MAX) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ fp = (struct free_arena_header *)sbrk(fsize);
+#else
+ fp = (struct free_arena_header *)
+ mmap(NULL, fsize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+#endif
+
+ if (fp == (struct free_arena_header *)MAP_FAILED) {
+ errno = ENOMEM;
+ return NULL; /* Failed to get a block */
+ }
+
+ /* Insert the block into the management chains. We need to set
+ up the size and the main block list pointer, the rest of
+ the work is logically identical to free(). */
+ fp->a.type = ARENA_TYPE_FREE;
+ fp->a.size = fsize;
+
+ /* We need to insert this into the main block list in the proper
+ place -- this list is required to be sorted. Since we most likely
+ get memory assignments in ascending order, search backwards for
+ the proper place. */
+ for (pah = __malloc_head.a.prev; pah->a.type != ARENA_TYPE_HEAD;
+ pah = pah->a.prev) {
+ if (pah < fp)
+ break;
+ }
+
+ /* Now pah points to the node that should be the predecessor of
+ the new node */
+ fp->a.next = pah->a.next;
+ fp->a.prev = pah;
+ pah->a.next = fp;
+ fp->a.next->a.prev = fp;
+
+ /* Insert into the free chain and coalesce with adjacent blocks */
+ fp = __free_block(fp);
+
+ /* Now we can allocate from this block */
+ return __malloc_from_block(fp, size);
+}
+
+void free(void *ptr)
+{
+ struct free_arena_header *ah;
+
+ if (!ptr)
+ return;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+#ifdef DEBUG_MALLOC
+ assert(ah->a.type == ARENA_TYPE_USED);
+#endif
+
+ /* Merge into adjacent free blocks */
+ ah = __free_block(ah);
+
+ /* See if it makes sense to return memory to the system */
+#if _KLIBC_MALLOC_USES_SBRK
+ if (ah->a.size >= _KLIBC_MALLOC_CHUNK_SIZE &&
+ (char *)ah + ah->a.size == __current_brk) {
+ remove_from_chains(ah);
+ brk(ah);
+ }
+#else
+ {
+ size_t page_size = getpagesize();
+ size_t page_mask = page_size - 1;
+ size_t head_portion = -(size_t)ah & page_mask;
+ size_t tail_portion = ((size_t)ah + ah->a.size) & page_mask;
+ size_t adj_size;
+
+ /* Careful here... an individual chunk of memory must have
+ a minimum size if it exists at all, so if either the
+ head or the tail is below the minimum, then extend
+ that chunk by a page. */
+
+ if (head_portion &&
+ head_portion < 2*sizeof(struct arena_header))
+ head_portion += page_size;
+
+ if (tail_portion &&
+ tail_portion < 2*sizeof(struct arena_header))
+ tail_portion += page_size;
+
+ adj_size = ah->a.size - head_portion - tail_portion;
+
+ /* Worth it? This is written the way it is to guard
+ against overflows... */
+ if (ah->a.size >= head_portion+tail_portion+
+ _KLIBC_MALLOC_CHUNK_SIZE) {
+ struct free_arena_header *tah, *tan, *tap;
+
+ if (tail_portion) {
+ /* Make a new header, and insert into chains
+ immediately after the current block */
+ tah = (struct free_arena_header *)
+ ((char *)ah + head_portion + adj_size);
+ tah->a.type = ARENA_TYPE_FREE;
+ tah->a.size = tail_portion;
+ tah->a.next = tan = ah->a.next;
+ tan->a.prev = tah;
+ tah->a.prev = ah;
+ ah->a.next = tah;
+ tah->prev_free = tap = ah->prev_free;
+ tap->next_free = tah;
+ tah->next_free = ah;
+ ah->prev_free = tah;
+ }
+
+ if (head_portion)
+ ah->a.size = head_portion;
+ else
+ remove_from_chains(ah);
+
+ munmap((char *)ah + head_portion, adj_size);
+ }
+ }
+#endif
+}
diff --git a/usr/klibc/malloc.h b/usr/klibc/malloc.h
new file mode 100644
index 0000000..af97a3f
--- /dev/null
+++ b/usr/klibc/malloc.h
@@ -0,0 +1,50 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <klibc/sysconfig.h>
+
+/*
+ * This structure should be a power of two. This becomes the
+ * alignment unit.
+ */
+struct free_arena_header;
+
+struct arena_header {
+ size_t type;
+ size_t size;
+ struct free_arena_header *next, *prev;
+};
+
+#ifdef DEBUG_MALLOC
+#define ARENA_TYPE_USED 0x64e69c70
+#define ARENA_TYPE_FREE 0x012d610a
+#define ARENA_TYPE_HEAD 0x971676b5
+#define ARENA_TYPE_DEAD 0xeeeeeeee
+#else
+#define ARENA_TYPE_USED 0
+#define ARENA_TYPE_FREE 1
+#define ARENA_TYPE_HEAD 2
+#endif
+
+#define MALLOC_CHUNK_MASK (_KLIBC_MALLOC_CHUNK_SIZE-1)
+
+#define ARENA_SIZE_MASK (~(sizeof(struct arena_header)-1))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+ struct arena_header a;
+ struct free_arena_header *next_free, *prev_free;
+};
+
+/*
+ * Internal variable used by brk/sbrk
+ */
+extern char *__current_brk;
diff --git a/usr/klibc/memccpy.c b/usr/klibc/memccpy.c
new file mode 100644
index 0000000..83d02c9
--- /dev/null
+++ b/usr/klibc/memccpy.c
@@ -0,0 +1,23 @@
+/*
+ * memccpy.c
+ *
+ * memccpy()
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memccpy(void *dst, const void *src, int c, size_t n)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while (n--) {
+ *q++ = ch = *p++;
+ if (ch == (char)c)
+ return q;
+ }
+
+ return NULL; /* No instance of "c" found */
+}
diff --git a/usr/klibc/memchr.c b/usr/klibc/memchr.c
new file mode 100644
index 0000000..f1947fb
--- /dev/null
+++ b/usr/klibc/memchr.c
@@ -0,0 +1,19 @@
+/*
+ * memchr.c
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+ const unsigned char *sp = s;
+
+ while (n--) {
+ if (*sp == (unsigned char)c)
+ return (void *)sp;
+ sp++;
+ }
+
+ return NULL;
+}
diff --git a/usr/klibc/memcmp.c b/usr/klibc/memcmp.c
new file mode 100644
index 0000000..3ce9941
--- /dev/null
+++ b/usr/klibc/memcmp.c
@@ -0,0 +1,19 @@
+/*
+ * memcmp.c
+ */
+
+#include <string.h>
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *c1 = s1, *c2 = s2;
+ int d = 0;
+
+ while (n--) {
+ d = (int)*c1++ - (int)*c2++;
+ if (d)
+ break;
+ }
+
+ return d;
+}
diff --git a/usr/klibc/memcpy.c b/usr/klibc/memcpy.c
new file mode 100644
index 0000000..5ce206d
--- /dev/null
+++ b/usr/klibc/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+ "+S"(p), "+D"(q)
+ :"r"(n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+ (nq), "+S"(p), "+D"(q)
+ :"r"((uint32_t) (n & 7)));
+#else
+ while (n--) {
+ *q++ = *p++;
+ }
+#endif
+
+ return dst;
+}
diff --git a/usr/klibc/memmem.c b/usr/klibc/memmem.c
new file mode 100644
index 0000000..72422aa
--- /dev/null
+++ b/usr/klibc/memmem.c
@@ -0,0 +1,55 @@
+/*
+ * memmem.c
+ *
+ * Find a byte string inside a longer byte string
+ *
+ * This uses the "Not So Naive" algorithm, a very simple but
+ * usually effective algorithm, see:
+ *
+ * http://www-igm.univ-mlv.fr/~lecroq/string/
+ */
+
+#include <string.h>
+
+void *memmem(const void *haystack, size_t n, const void *needle, size_t m)
+{
+ const unsigned char *y = (const unsigned char *)haystack;
+ const unsigned char *x = (const unsigned char *)needle;
+
+ size_t j, k, l;
+
+ if (!m)
+ return (void *)haystack;
+
+ if (m > n)
+ return NULL;
+
+ if (1 != m) {
+ if (x[0] == x[1]) {
+ k = 2;
+ l = 1;
+ } else {
+ k = 1;
+ l = 2;
+ }
+
+ j = 0;
+ while (j <= n - m) {
+ if (x[1] != y[j + 1]) {
+ j += k;
+ } else {
+ if (!memcmp(x + 2, y + j + 2, m - 2)
+ && x[0] == y[j])
+ return (void *)&y[j];
+ j += l;
+ }
+ }
+ } else
+ do {
+ if (*y == *x)
+ return (void *)y;
+ y++;
+ } while (--n);
+
+ return NULL;
+}
diff --git a/usr/klibc/memmove.c b/usr/klibc/memmove.c
new file mode 100644
index 0000000..a398cd8
--- /dev/null
+++ b/usr/klibc/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+ const char *p = src;
+ char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+ if (q < p) {
+ asm volatile("cld; rep; movsb"
+ : "+c" (n), "+S"(p), "+D"(q));
+ } else {
+ p += (n - 1);
+ q += (n - 1);
+ asm volatile("std; rep; movsb; cld"
+ : "+c" (n), "+S"(p), "+D"(q));
+ }
+#else
+ if (q < p) {
+ while (n--) {
+ *q++ = *p++;
+ }
+ } else {
+ p += n;
+ q += n;
+ while (n--) {
+ *--q = *--p;
+ }
+ }
+#endif
+
+ return dst;
+}
diff --git a/usr/klibc/memrchr.c b/usr/klibc/memrchr.c
new file mode 100644
index 0000000..ff6d711
--- /dev/null
+++ b/usr/klibc/memrchr.c
@@ -0,0 +1,19 @@
+/*
+ * memrchr.c
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+void *memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *sp = (const unsigned char *)s + n - 1;
+
+ while (n--) {
+ if (*sp == (unsigned char)c)
+ return (void *)sp;
+ sp--;
+ }
+
+ return NULL;
+}
diff --git a/usr/klibc/memset.c b/usr/klibc/memset.c
new file mode 100644
index 0000000..aa00b5b
--- /dev/null
+++ b/usr/klibc/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+ char *q = dst;
+
+#if defined(__i386__)
+ size_t nl = n >> 2;
+ asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+ : "+c" (nl), "+D" (q)
+ : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+ size_t nq = n >> 3;
+ asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+ :"+c" (nq), "+D" (q)
+ : "a" ((unsigned char)c * 0x0101010101010101U),
+ "r" ((uint32_t) n & 7));
+#else
+ while (n--) {
+ *q++ = c;
+ }
+#endif
+
+ return dst;
+}
diff --git a/usr/klibc/memswap.c b/usr/klibc/memswap.c
new file mode 100644
index 0000000..b32315c
--- /dev/null
+++ b/usr/klibc/memswap.c
@@ -0,0 +1,24 @@
+/*
+ * memswap()
+ *
+ * Swaps the contents of two nonoverlapping memory areas.
+ * This really could be done faster...
+ */
+
+#include <string.h>
+
+void memswap(void *m1, void *m2, size_t n)
+{
+ char *p = m1;
+ char *q = m2;
+ char tmp;
+
+ while (n--) {
+ tmp = *p;
+ *p = *q;
+ *q = tmp;
+
+ p++;
+ q++;
+ }
+}
diff --git a/usr/klibc/mkdir.c b/usr/klibc/mkdir.c
new file mode 100644
index 0000000..27673e3
--- /dev/null
+++ b/usr/klibc/mkdir.c
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_mkdir
+
+int mkdir(const char *pathname, mode_t mode)
+{
+ return mkdirat(AT_FDCWD, pathname, mode);
+}
+
+#endif /* __NR_mkdir */
diff --git a/usr/klibc/mknod.c b/usr/klibc/mknod.c
new file mode 100644
index 0000000..727505f
--- /dev/null
+++ b/usr/klibc/mknod.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_mknod
+
+int mknod(const char *pathname, mode_t mode, dev_t dev)
+{
+ return mknodat(AT_FDCWD, pathname, mode, dev);
+}
+
+#endif /* __NR_mknod */
diff --git a/usr/klibc/mmap.c b/usr/klibc/mmap.c
new file mode 100644
index 0000000..2c427ca
--- /dev/null
+++ b/usr/klibc/mmap.c
@@ -0,0 +1,40 @@
+/*
+ * mmap.c
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <bitsize.h>
+#include <klibc/sysconfig.h>
+
+/*
+ * Set in SYSCALLS whether or not we should use an unadorned mmap() system
+ * call (typical on 64-bit architectures).
+ */
+#if _KLIBC_USE_MMAP2
+
+/* This architecture uses mmap2(). The Linux mmap2() system call takes
+ a page offset as the offset argument. We need to make sure we have
+ the proper conversion in place. */
+
+extern void *__mmap2(void *, size_t, int, int, int, size_t);
+
+void *mmap(void *start, size_t length, int prot, int flags, int fd,
+ off_t offset)
+{
+ const int mmap2_shift = _KLIBC_MMAP2_SHIFT;
+ const off_t mmap2_mask = ((off_t) 1 << mmap2_shift) - 1;
+
+ if (offset & mmap2_mask) {
+ errno = EINVAL;
+ return MAP_FAILED;
+ }
+
+ return __mmap2(start, length, prot, flags, fd,
+ (size_t) offset >> mmap2_shift);
+}
+
+#endif
diff --git a/usr/klibc/mrand48.c b/usr/klibc/mrand48.c
new file mode 100644
index 0000000..e3b73cc
--- /dev/null
+++ b/usr/klibc/mrand48.c
@@ -0,0 +1,13 @@
+/*
+ * mrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3]; /* Common with lrand48.c, srand48.c */
+
+long mrand48(void)
+{
+ return jrand48(__rand48_seed);
+}
diff --git a/usr/klibc/nanosleep.c b/usr/klibc/nanosleep.c
new file mode 100644
index 0000000..1141219
--- /dev/null
+++ b/usr/klibc/nanosleep.c
@@ -0,0 +1,8 @@
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+int nanosleep(const struct timespec *request, struct timespec *remain)
+{
+ return clock_nanosleep(CLOCK_MONOTONIC, 0, request, remain) ? -1 : 0;
+}
diff --git a/usr/klibc/nice.c b/usr/klibc/nice.c
new file mode 100644
index 0000000..e6e99ac
--- /dev/null
+++ b/usr/klibc/nice.c
@@ -0,0 +1,19 @@
+/*
+ * nice.c
+ */
+
+#include <unistd.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_nice
+
+int nice(int inc)
+{
+ pid_t me = getpid();
+ return setpriority(me, PRIO_PROCESS,
+ getpriority(me, PRIO_PROCESS) + inc);
+}
+
+#endif
diff --git a/usr/klibc/nrand48.c b/usr/klibc/nrand48.c
new file mode 100644
index 0000000..cb3532b
--- /dev/null
+++ b/usr/klibc/nrand48.c
@@ -0,0 +1,11 @@
+/*
+ * nrand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+long nrand48(unsigned short xsubi[3])
+{
+ return (long)((uint32_t) jrand48(xsubi) >> 1);
+}
diff --git a/usr/klibc/nullenv.c b/usr/klibc/nullenv.c
new file mode 100644
index 0000000..ba7e71c
--- /dev/null
+++ b/usr/klibc/nullenv.c
@@ -0,0 +1,8 @@
+/*
+ * nullenv.c
+ */
+
+#include <stddef.h>
+#include "env.h"
+
+char * const __null_environ[] = { NULL };
diff --git a/usr/klibc/onexit.c b/usr/klibc/onexit.c
new file mode 100644
index 0000000..15a96b5
--- /dev/null
+++ b/usr/klibc/onexit.c
@@ -0,0 +1,23 @@
+/*
+ * onexit.c
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "atexit.h"
+
+int on_exit(void (*fctn) (int, void *), void *arg)
+{
+ struct atexit *as = malloc(sizeof(struct atexit));
+
+ if (!as)
+ return -1;
+
+ as->fctn = fctn;
+ as->arg = arg;
+
+ as->next = __atexit_list;
+ __atexit_list = as;
+
+ return 0;
+}
diff --git a/usr/klibc/open.c b/usr/klibc/open.c
new file mode 100644
index 0000000..5305c3d
--- /dev/null
+++ b/usr/klibc/open.c
@@ -0,0 +1,47 @@
+/*
+ * open.c
+ *
+ * On 32-bit platforms we need to pass O_LARGEFILE to the open()
+ * system call, to indicate that we're 64-bit safe.
+ *
+ * For 64 bit systems without the open syscall, pass straight
+ * through into openat.
+ */
+
+#define _KLIBC_IN_OPEN_C
+#include <unistd.h>
+#include <fcntl.h>
+#include <bitsize.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_open
+#if _BITSIZE == 32
+
+extern int __openat(int, const char *, int, mode_t);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+ return __openat(AT_FDCWD, pathname, flags | O_LARGEFILE, mode);
+}
+
+#else
+
+__extern int openat(int, const char *, int, ...);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+ return openat(AT_FDCWD, pathname, flags, mode);
+}
+
+#endif /* _BITSIZE == 32 */
+
+#elif _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__)
+
+extern int __open(const char *, int, mode_t);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+ return __open(pathname, flags | O_LARGEFILE, mode);
+}
+
+#endif /* __NR_open */
diff --git a/usr/klibc/openat.c b/usr/klibc/openat.c
new file mode 100644
index 0000000..8e5baa0
--- /dev/null
+++ b/usr/klibc/openat.c
@@ -0,0 +1,22 @@
+/*
+ * openat.c
+ *
+ * On 32-bit platforms we need to pass O_LARGEFILE to the openat()
+ * system call, to indicate that we're 64-bit safe.
+ */
+
+#define _KLIBC_IN_OPEN_C
+#include <unistd.h>
+#include <fcntl.h>
+#include <bitsize.h>
+
+#if _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__) && defined(__NR_openat)
+
+extern int __openat(int, const char *, int, mode_t);
+
+int openat(int dirfd, const char *pathname, int flags, mode_t mode)
+{
+ return __openat(dirfd, pathname, flags | O_LARGEFILE, mode);
+}
+
+#endif
diff --git a/usr/klibc/pause.c b/usr/klibc/pause.c
new file mode 100644
index 0000000..cec97a8
--- /dev/null
+++ b/usr/klibc/pause.c
@@ -0,0 +1,17 @@
+/*
+ * pause.c
+ */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_pause
+
+int pause(void)
+{
+ return select(0, NULL, NULL, NULL, NULL);
+}
+
+#endif
diff --git a/usr/klibc/perror.c b/usr/klibc/perror.c
new file mode 100644
index 0000000..3177057
--- /dev/null
+++ b/usr/klibc/perror.c
@@ -0,0 +1,13 @@
+/*
+ * perror.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+void perror(const char *s)
+{
+ int e = errno;
+ fprintf(stderr, "%s: %s\n", s, strerror(e));
+}
diff --git a/usr/klibc/pipe.c b/usr/klibc/pipe.c
new file mode 100644
index 0000000..dfaed9e
--- /dev/null
+++ b/usr/klibc/pipe.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_pipe
+
+int pipe(int pipefd[2])
+{
+ return pipe2(pipefd, 0);
+}
+
+#endif /* __NR_pipe */
diff --git a/usr/klibc/poll.c b/usr/klibc/poll.c
new file mode 100644
index 0000000..f539b99
--- /dev/null
+++ b/usr/klibc/poll.c
@@ -0,0 +1,21 @@
+#include <errno.h>
+#include <sys/poll.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_poll
+
+int poll(struct pollfd *fds, nfds_t nfds, long timeout)
+{
+ struct timespec timeout_ts;
+ struct timespec *timeout_ts_p = NULL;
+
+ if (timeout >= 0) {
+ timeout_ts.tv_sec = timeout / 1000;
+ timeout_ts.tv_nsec = (timeout % 1000) * 1000000;
+ timeout_ts_p = &timeout_ts;
+ }
+
+ return ppoll(fds, nfds, timeout_ts_p, 0);
+}
+
+#endif /* __NR_poll */
diff --git a/usr/klibc/ppoll.c b/usr/klibc/ppoll.c
new file mode 100644
index 0000000..5e20a89
--- /dev/null
+++ b/usr/klibc/ppoll.c
@@ -0,0 +1,19 @@
+/*
+ * ppoll.c
+ */
+
+#include <sys/poll.h>
+#include <sys/syscall.h>
+
+#ifdef __NR_ppoll
+
+__extern int __ppoll(struct pollfd *, nfds_t, struct timespec *,
+ const sigset_t *, size_t);
+
+int ppoll(struct pollfd *ufds, nfds_t nfds, struct timespec *timeout,
+ const sigset_t * sigmask)
+{
+ return __ppoll(ufds, nfds, timeout, sigmask, sizeof *sigmask);
+}
+
+#endif
diff --git a/usr/klibc/pread.c b/usr/klibc/pread.c
new file mode 100644
index 0000000..1ac3075
--- /dev/null
+++ b/usr/klibc/pread.c
@@ -0,0 +1,30 @@
+/*
+ * pread.c
+ *
+ * Some architectures need to wrap the system call
+ */
+
+#include <sys/types.h>
+#include <endian.h>
+#include <sys/syscall.h>
+
+#if defined(__hppa__)
+
+#if _BITSIZE == 32
+extern size_t __pread(int, void *, size_t, unsigned int, unsigned int);
+#else
+extern size_t __pread(int, void *, size_t, off_t);
+#endif
+
+size_t pread(int fd, void *buf, size_t count, off_t offset)
+{
+#if _BITSIZE == 32
+ unsigned int hi = offset >> 32;
+ unsigned int lo = (unsigned int) offset;
+ return __pread(fd, buf, count, __LONG_LONG_PAIR(hi, lo));
+#else
+ return __pread(fd, buf, count, offset);
+#endif
+}
+
+#endif
diff --git a/usr/klibc/printf.c b/usr/klibc/printf.c
new file mode 100644
index 0000000..02bdba0
--- /dev/null
+++ b/usr/klibc/printf.c
@@ -0,0 +1,19 @@
+/*
+ * printf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define BUFFER_SIZE 16384
+
+int printf(const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vfprintf(stdout, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/usr/klibc/pselect.c b/usr/klibc/pselect.c
new file mode 100644
index 0000000..42777f9
--- /dev/null
+++ b/usr/klibc/pselect.c
@@ -0,0 +1,22 @@
+/*
+ * pselect.c
+ */
+
+#include <sys/select.h>
+#include <sys/syscall.h>
+
+struct __pselect6 {
+ const sigset_t *sigmask;
+ size_t sigsize;
+};
+
+__extern int __pselect6(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const struct __pselect6 *);
+
+int pselect(int n, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+ const struct timespec *timeout, const sigset_t * sigmask)
+{
+ struct __pselect6 extended_sigmask = { sigmask, sizeof *sigmask };
+ return __pselect6(n, readfds, writefds, exceptfds,
+ timeout, &extended_sigmask);
+}
diff --git a/usr/klibc/pty.c b/usr/klibc/pty.c
new file mode 100644
index 0000000..7fcb2ba
--- /dev/null
+++ b/usr/klibc/pty.c
@@ -0,0 +1,31 @@
+/*
+ * pty.c
+ *
+ * Basic Unix98 PTY functionality; assumes devpts mounted on /dev/pts
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+char *ptsname(int fd)
+{
+ static char buffer[32]; /* Big enough to hold even a 64-bit pts no */
+ unsigned int ptyno;
+
+ if (ioctl(fd, TIOCGPTN, &ptyno))
+ return NULL;
+
+ snprintf(buffer, sizeof buffer, "/dev/pts/%u", ptyno);
+
+ return buffer;
+}
+
+int unlockpt(int fd)
+{
+ int unlock = 0;
+
+ return ioctl(fd, TIOCSPTLCK, &unlock);
+}
diff --git a/usr/klibc/putchar.c b/usr/klibc/putchar.c
new file mode 100644
index 0000000..e2224ca
--- /dev/null
+++ b/usr/klibc/putchar.c
@@ -0,0 +1,15 @@
+/*
+ * putchar.c
+ *
+ * - gcc wants this
+ */
+
+#include <stdio.h>
+
+#undef putchar /* Defined as a macro */
+int putchar(int);
+
+int putchar(int c)
+{
+ return fputc(c, stdout);
+}
diff --git a/usr/klibc/putenv.c b/usr/klibc/putenv.c
new file mode 100644
index 0000000..5059ecb
--- /dev/null
+++ b/usr/klibc/putenv.c
@@ -0,0 +1,37 @@
+/*
+ * putenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int putenv(const char *str)
+{
+ char *s;
+ const char *e, *z;
+
+ if (!str) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ e = NULL;
+ for (z = str; *z; z++) {
+ if (*z == '=')
+ e = z;
+ }
+
+ if (!e) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ s = strdup(str);
+ if (!s)
+ return -1;
+
+ return __put_env(s, e - str, 1);
+}
diff --git a/usr/klibc/puts.c b/usr/klibc/puts.c
new file mode 100644
index 0000000..27e16e2
--- /dev/null
+++ b/usr/klibc/puts.c
@@ -0,0 +1,13 @@
+/*
+ * puts.c
+ */
+
+#include <stdio.h>
+
+int puts(const char *s)
+{
+ if (fputs(s, stdout) < 0)
+ return -1;
+
+ return _fwrite("\n", 1, stdout);
+}
diff --git a/usr/klibc/pwrite.c b/usr/klibc/pwrite.c
new file mode 100644
index 0000000..19b219f
--- /dev/null
+++ b/usr/klibc/pwrite.c
@@ -0,0 +1,30 @@
+/*
+ * pwrite.c
+ *
+ * Some architectures need to wrap the system call
+ */
+
+#include <sys/types.h>
+#include <endian.h>
+#include <sys/syscall.h>
+
+#if defined(__hppa__)
+
+#if _BITSIZE == 32
+extern ssize_t __pwrite(int, const void *, size_t, unsigned int, unsigned int);
+#else
+extern ssize_t __pwrite(int, const void *, size_t, off_t);
+#endif
+
+size_t pwrite(int fd, void *buf, size_t count, off_t offset)
+{
+#if _BITSIZE == 32
+ unsigned int hi = offset >> 32;
+ unsigned int lo = (unsigned int) offset;
+ return __pwrite(fd, buf, count, __LONG_LONG_PAIR(hi, lo));
+#else
+ return __pwrite(fd, buf, count, offset);
+#endif
+}
+
+#endif
diff --git a/usr/klibc/qsort.c b/usr/klibc/qsort.c
new file mode 100644
index 0000000..4c189fc
--- /dev/null
+++ b/usr/klibc/qsort.c
@@ -0,0 +1,46 @@
+/*
+ * qsort.c
+ *
+ * This is actually combsort. It's an O(n log n) algorithm with
+ * simplicity/small code size being its main virtue.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+static inline size_t newgap(size_t gap)
+{
+ gap = (gap * 10) / 13;
+ if (gap == 9 || gap == 10)
+ gap = 11;
+
+ if (gap < 1)
+ gap = 1;
+ return gap;
+}
+
+void qsort(void *base, size_t nmemb, size_t size,
+ int (*compar) (const void *, const void *))
+{
+ size_t gap = nmemb;
+ size_t i, j;
+ char *p1, *p2;
+ int swapped;
+
+ if (!nmemb)
+ return;
+
+ do {
+ gap = newgap(gap);
+ swapped = 0;
+
+ for (i = 0, p1 = base; i < nmemb - gap; i++, p1 += size) {
+ j = i + gap;
+ if (compar(p1, p2 = (char *)base + j * size) > 0) {
+ memswap(p1, p2, size);
+ swapped = 1;
+ }
+ }
+ } while (gap > 1 || swapped);
+}
diff --git a/usr/klibc/raise.c b/usr/klibc/raise.c
new file mode 100644
index 0000000..3b9d23d
--- /dev/null
+++ b/usr/klibc/raise.c
@@ -0,0 +1,11 @@
+/*
+ * raise.c
+ */
+
+#include <unistd.h>
+#include <signal.h>
+
+int raise(int signal)
+{
+ return kill(getpid(), signal);
+}
diff --git a/usr/klibc/readdir.c b/usr/klibc/readdir.c
new file mode 100644
index 0000000..8134c92
--- /dev/null
+++ b/usr/klibc/readdir.c
@@ -0,0 +1,68 @@
+/*
+ * readdir.c: opendir/readdir/closedir
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define __KLIBC_DIRENT_INTERNALS
+#include <dirent.h>
+
+DIR *fdopendir(int fd)
+{
+ DIR *dp = zalloc(sizeof(DIR));
+
+ if (!dp)
+ return NULL;
+
+ dp->__fd = fd;
+ return dp;
+}
+
+DIR *opendir(const char *name)
+{
+ int fd, err;
+ DIR *dp;
+
+ fd = open(name, O_DIRECTORY | O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ dp = fdopendir(fd);
+ if (!dp) {
+ err = errno;
+ close(fd);
+ errno = err;
+ }
+ return dp;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *dent;
+ int rv;
+
+ if (!dir->bytes_left) {
+ rv = getdents(dir->__fd, dir->buffer, sizeof(dir->buffer));
+ if (rv <= 0)
+ return NULL;
+ dir->bytes_left = rv;
+ dir->next = dir->buffer;
+ }
+
+ dent = dir->next;
+ dir->next = (struct dirent *)((char *)dir->next + dent->d_reclen);
+ dir->bytes_left -= dent->d_reclen;
+
+ return dent;
+}
+
+int closedir(DIR *dir)
+{
+ int rv;
+ rv = close(dir->__fd);
+ free(dir);
+ return rv;
+}
diff --git a/usr/klibc/readlink.c b/usr/klibc/readlink.c
new file mode 100644
index 0000000..0e67442
--- /dev/null
+++ b/usr/klibc/readlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_readlink
+
+int readlink(const char *path, char *buf, size_t bufsiz)
+{
+ return readlinkat(AT_FDCWD, path, buf, bufsiz);
+}
+
+#endif /* __NR_readlink */
diff --git a/usr/klibc/realloc.c b/usr/klibc/realloc.c
new file mode 100644
index 0000000..14a2f2f
--- /dev/null
+++ b/usr/klibc/realloc.c
@@ -0,0 +1,48 @@
+/*
+ * realloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "malloc.h"
+
+/* FIXME: This is cheesy, it should be fixed later */
+
+void *realloc(void *ptr, size_t size)
+{
+ struct free_arena_header *ah;
+ void *newptr;
+ size_t oldsize;
+
+ if (!ptr)
+ return malloc(size);
+
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ }
+
+ /* Add the obligatory arena header, and round up */
+ size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+ if (ah->a.size >= size && size >= (ah->a.size >> 2)) {
+ /* This field is a good size already. */
+ return ptr;
+ } else {
+ /* Make me a new block. This is kind of bogus; we should
+ be checking the following block to see if we can do an
+ in-place adjustment... fix that later. */
+
+ oldsize = ah->a.size - sizeof(struct arena_header);
+
+ newptr = malloc(size);
+ memcpy(newptr, ptr, (size < oldsize) ? size : oldsize);
+ free(ptr);
+
+ return newptr;
+ }
+}
diff --git a/usr/klibc/realpath.c b/usr/klibc/realpath.c
new file mode 100644
index 0000000..1474b1e
--- /dev/null
+++ b/usr/klibc/realpath.c
@@ -0,0 +1,49 @@
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * Note that this requires name to refer to an existing file. This is
+ * correct according to POSIX. However, BSD and GNU implementations
+ * also allow name to refer to a non-existing file in an existing
+ * directory.
+ */
+
+char *realpath(const char *name, char *resolved_name)
+{
+ static const char proc_fd_prefix[] = "/proc/self/fd/";
+ char proc_fd_name[sizeof(proc_fd_prefix) + sizeof(int) * 3];
+ int allocated = 0;
+ int fd;
+ ssize_t len;
+
+ /* Open for path lookup only */
+ fd = open(name, O_PATH);
+ if (fd < 0)
+ return NULL;
+
+ if (!resolved_name) {
+ resolved_name = malloc(PATH_MAX);
+ if (!resolved_name)
+ goto out_close;
+ allocated = 1;
+ }
+
+ /* Use procfs to read back the resolved name */
+ sprintf(proc_fd_name, "%s%d", proc_fd_prefix, fd);
+ len = readlink(proc_fd_name, resolved_name, PATH_MAX - 1);
+ if (len < 0) {
+ if (allocated)
+ free(resolved_name);
+ resolved_name = NULL;
+ } else {
+ resolved_name[len] = 0;
+ }
+
+out_close:
+ close(fd);
+ return resolved_name;
+}
diff --git a/usr/klibc/reboot.c b/usr/klibc/reboot.c
new file mode 100644
index 0000000..5aab039
--- /dev/null
+++ b/usr/klibc/reboot.c
@@ -0,0 +1,15 @@
+/*
+ * reboot.c
+ */
+
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+
+/* This provides two-argument reboot function (glibc flag plus reboot argument).
+ The full four-argument system call is available as __reboot(). */
+
+int reboot(int flag, void *arg)
+{
+ return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, flag, arg);
+}
diff --git a/usr/klibc/recv.c b/usr/klibc/recv.c
new file mode 100644
index 0000000..0baa00a
--- /dev/null
+++ b/usr/klibc/recv.c
@@ -0,0 +1,11 @@
+/*
+ * recv.c
+ */
+
+#include <stddef.h>
+#include <sys/socket.h>
+
+int recv(int s, void *buf, size_t len, unsigned int flags)
+{
+ return recvfrom(s, buf, len, flags, NULL, 0);
+}
diff --git a/usr/klibc/remove.c b/usr/klibc/remove.c
new file mode 100644
index 0000000..9088204
--- /dev/null
+++ b/usr/klibc/remove.c
@@ -0,0 +1,18 @@
+/*
+ * remove.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+int remove(const char *pathname)
+{
+ int rv;
+
+ rv = unlink(pathname);
+ if (rv == -1 && errno == EISDIR)
+ return rmdir(pathname);
+
+ return rv;
+}
diff --git a/usr/klibc/rename.c b/usr/klibc/rename.c
new file mode 100644
index 0000000..d76b739
--- /dev/null
+++ b/usr/klibc/rename.c
@@ -0,0 +1,11 @@
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifndef __NR_rename
+
+int rename(const char *oldpath, const char *newpath)
+{
+ return renameat2(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
+}
+
+#endif /* __NR_rename */
diff --git a/usr/klibc/renameat.c b/usr/klibc/renameat.c
new file mode 100644
index 0000000..10c8882
--- /dev/null
+++ b/usr/klibc/renameat.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifndef __NR_renameat
+
+int renameat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath)
+{
+ return renameat2(olddirfd, oldpath, newdirfd, newpath, 0);
+}
+
+#endif /* __NR_renameat */
diff --git a/usr/klibc/rmdir.c b/usr/klibc/rmdir.c
new file mode 100644
index 0000000..94ae5f2
--- /dev/null
+++ b/usr/klibc/rmdir.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_rmdir
+
+int rmdir(const char *pathname)
+{
+ return unlinkat(AT_FDCWD, pathname, AT_REMOVEDIR);
+}
+
+#endif /* __NR_rmdir */
diff --git a/usr/klibc/sbrk.c b/usr/klibc/sbrk.c
new file mode 100644
index 0000000..4896ce0
--- /dev/null
+++ b/usr/klibc/sbrk.c
@@ -0,0 +1,45 @@
+/* sbrk.c - Change data segment size */
+
+/* Written 2000 by Werner Almesberger */
+/* Modified 2003-2004 for klibc by H. Peter Anvin */
+
+#include <stddef.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "malloc.h"
+
+#if !_KLIBC_NO_MMU /* uClinux doesn't have brk() */
+
+char *__current_brk; /* Common with brk.c */
+
+/* p is an address, a is alignment; must be a power of 2 */
+static inline void *align_up(void *p, uintptr_t a)
+{
+ return (void *)(((uintptr_t) p + a - 1) & ~(a - 1));
+}
+
+void *sbrk(ptrdiff_t increment)
+{
+ char *start, *end, *new_brk;
+
+ if (!__current_brk)
+ __current_brk = __brk(NULL);
+
+ start = align_up(__current_brk, _KLIBC_SBRK_ALIGNMENT);
+ end = start + increment;
+
+ new_brk = __brk(end);
+
+ if (new_brk == (void *)-1)
+ return (void *)-1;
+ else if (new_brk < end) {
+ errno = ENOMEM;
+ return (void *)-1;
+ }
+
+ __current_brk = new_brk;
+ return start;
+}
+
+#endif /* !_KLIBC_NO_MMU */
diff --git a/usr/klibc/scandir.c b/usr/klibc/scandir.c
new file mode 100644
index 0000000..9b95980
--- /dev/null
+++ b/usr/klibc/scandir.c
@@ -0,0 +1,71 @@
+/*
+ * scandir.c: scandir
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <dirent.h>
+
+int scandir(const char *dirp, struct dirent ***namelist,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **))
+{
+ struct dirent **nl = NULL, **next_nl;
+ struct dirent *dirent;
+ size_t count = 0;
+ size_t allocated = 0;
+ DIR *dir;
+
+ dir = opendir(dirp);
+ if (!dir)
+ return -1;
+
+ while (1) {
+ dirent = readdir(dir);
+ if (!dirent)
+ break;
+ if (!filter || filter(dirent)) {
+ struct dirent *copy;
+ copy = malloc(sizeof(*copy));
+ if (!copy)
+ goto cleanup_fail;
+ memcpy(copy, dirent, sizeof(*copy));
+
+ /* Extend the array if needed */
+ if (count == allocated) {
+ if (allocated == 0)
+ allocated = 15; /* ~1 page worth */
+ else
+ allocated *= 2;
+ next_nl = realloc(nl, allocated);
+ if (!next_nl) {
+ free(copy);
+ goto cleanup_fail;
+ }
+ nl = next_nl;
+ }
+
+ nl[count++] = copy;
+ }
+ }
+
+ qsort(nl, count, sizeof(struct dirent *),
+ (int (*)(const void *, const void *))compar);
+
+ closedir(dir);
+
+ *namelist = nl;
+ return count;
+
+cleanup_fail:
+ while (count) {
+ dirent = nl[--count];
+ free(dirent);
+ }
+ free(nl);
+ closedir(dir);
+ errno = ENOMEM;
+ return -1;
+}
diff --git a/usr/klibc/seed48.c b/usr/klibc/seed48.c
new file mode 100644
index 0000000..ccdf183
--- /dev/null
+++ b/usr/klibc/seed48.c
@@ -0,0 +1,18 @@
+/*
+ * seed48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+unsigned short __rand48_seed[3];
+
+unsigned short *seed48(const unsigned short xsubi[3])
+{
+ static unsigned short oldseed[3];
+ memcpy(oldseed, __rand48_seed, sizeof __rand48_seed);
+ memcpy(__rand48_seed, xsubi, sizeof __rand48_seed);
+
+ return oldseed;
+}
diff --git a/usr/klibc/select.c b/usr/klibc/select.c
new file mode 100644
index 0000000..11e7154
--- /dev/null
+++ b/usr/klibc/select.c
@@ -0,0 +1,31 @@
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <sys/syscall.h>
+
+struct __pselect6;
+__extern int __pselect6(int, fd_set *, fd_set *, fd_set *,
+ const struct timespec *, const struct __pselect6 *);
+
+int select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+ int result;
+ struct timespec ts;
+
+ if (timeout) {
+ ts.tv_sec = timeout->tv_sec;
+ ts.tv_nsec = timeout->tv_usec * 1000;
+ }
+
+ result = __pselect6(nfds, readfds, writefds, exceptfds,
+ timeout ? &ts : NULL, NULL);
+
+ if (timeout) {
+ timeout->tv_sec = ts.tv_sec;
+ timeout->tv_usec = ts.tv_nsec / 1000;
+ }
+
+ return result;
+}
diff --git a/usr/klibc/send.c b/usr/klibc/send.c
new file mode 100644
index 0000000..a867dd1
--- /dev/null
+++ b/usr/klibc/send.c
@@ -0,0 +1,11 @@
+/*
+ * send.c
+ */
+
+#include <stddef.h>
+#include <sys/socket.h>
+
+int send(int s, const void *buf, size_t len, unsigned int flags)
+{
+ return sendto(s, buf, len, flags, NULL, 0);
+}
diff --git a/usr/klibc/setegid.c b/usr/klibc/setegid.c
new file mode 100644
index 0000000..6af966f
--- /dev/null
+++ b/usr/klibc/setegid.c
@@ -0,0 +1,10 @@
+/*
+ * setegid.c
+ */
+
+#include <unistd.h>
+
+int setegid(gid_t egid)
+{
+ return setregid(-1, egid);
+}
diff --git a/usr/klibc/setenv.c b/usr/klibc/setenv.c
new file mode 100644
index 0000000..45a7aad
--- /dev/null
+++ b/usr/klibc/setenv.c
@@ -0,0 +1,42 @@
+/*
+ * setenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int setenv(const char *name, const char *val, int overwrite)
+{
+ const char *z;
+ char *s;
+ size_t l1, l2;
+
+ if (!name || !name[0]) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ l1 = 0;
+ for (z = name; *z; z++) {
+ l1++;
+ if (*z == '=') {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ l2 = strlen(val);
+
+ s = malloc(l1 + l2 + 2);
+ if (!s)
+ return -1;
+
+ memcpy(s, name, l1);
+ s[l1] = '=';
+ memcpy(s + l1 + 1, val, l2 + 1);
+
+ return __put_env(s, l1 + 1, overwrite);
+}
diff --git a/usr/klibc/seteuid.c b/usr/klibc/seteuid.c
new file mode 100644
index 0000000..18dddb1
--- /dev/null
+++ b/usr/klibc/seteuid.c
@@ -0,0 +1,10 @@
+/*
+ * seteuid.c
+ */
+
+#include <unistd.h>
+
+int seteuid(uid_t euid)
+{
+ return setreuid(-1, euid);
+}
diff --git a/usr/klibc/setmntent.c b/usr/klibc/setmntent.c
new file mode 100644
index 0000000..d23e141
--- /dev/null
+++ b/usr/klibc/setmntent.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <mntent.h>
+
+FILE *setmntent(const char *filename, const char *type)
+{
+ return fopen(filename, type);
+}
diff --git a/usr/klibc/setpgrp.c b/usr/klibc/setpgrp.c
new file mode 100644
index 0000000..75bbcc7
--- /dev/null
+++ b/usr/klibc/setpgrp.c
@@ -0,0 +1,10 @@
+/*
+ * setpgrp.c
+ */
+
+#include <unistd.h>
+
+int setpgrp(void)
+{
+ return setpgid(0, 0);
+}
diff --git a/usr/klibc/settimeofday.c b/usr/klibc/settimeofday.c
new file mode 100644
index 0000000..75754db
--- /dev/null
+++ b/usr/klibc/settimeofday.c
@@ -0,0 +1,22 @@
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+extern int __settimeofday(const void *, const struct timezone *);
+
+int settimeofday(const struct timeval *tv, const struct timezone *tz)
+{
+ struct timespec ts;
+
+ if (tz && __settimeofday(NULL, tz))
+ return -1;
+
+ if (tv) {
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ if (clock_settime(CLOCK_REALTIME, &ts))
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/sha1hash.c b/usr/klibc/sha1hash.c
new file mode 100644
index 0000000..c29eebf
--- /dev/null
+++ b/usr/klibc/sha1hash.c
@@ -0,0 +1,317 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it. This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 2/03
+By H. Peter Anvin <hpa@zytor.com>
+Still 100% PD
+Modified to run on any hardware with <inttypes.h> and <netinet/in.h>
+Changed the driver program
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define SHA1HANDSOFF */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */
+
+/* #include <process.h> */ /* prototype for exit() - JHB */
+/* Using return() instead of exit() - SWR */
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX* context);
+void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len); /*
+JHB */
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#define blk0(i) (block->l[i] = ntohl(block->l[i]))
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+#ifdef VERBOSE /* SAK */
+void SHAPrintContext(SHA1_CTX *context, char *msg){
+ printf("%s (%d,%d) %x %x %x %x %x\n",
+ msg,
+ context->count[0], context->count[1],
+ context->state[0],
+ context->state[1],
+ context->state[2],
+ context->state[3],
+ context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], unsigned char buffer[64])
+{
+uint32_t a, b, c, d, e;
+typedef union {
+ unsigned char c[64];
+ uint32_t l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+ block = (CHAR64LONG16*)workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16*)buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len) /*
+JHB */
+{
+uint32_t i, j; /* JHB */
+
+#ifdef VERBOSE
+ SHAPrintContext(context, "before");
+#endif
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+ SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+uint32_t i; /* JHB */
+unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform()
+*/
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ /* Wipe variables */
+ i = 0; /* JHB */
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(finalcount, 0, 8); /* SWR */
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/*************************************************************/
+
+/* This is not quite the MIME base64 algorithm: it uses _ instead of /,
+ and instead of padding the output with = characters we just make the
+ output shorter. */
+char *mybase64(uint8_t digest[20])
+{
+ static const char charz[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ uint8_t input[21];
+ static char output[28];
+ int i, j;
+ uint8_t *p;
+ char *q;
+ uint32_t bv;
+
+ memcpy(input, digest, 20);
+ input[20] = 0; /* Pad to multiple of 3 bytes */
+
+ p = input; q = output;
+ for ( i = 0 ; i < 7 ; i++ ) {
+ bv = (p[0] << 16) | (p[1] << 8) | p[2];
+ p += 3;
+ for ( j = 0 ; j < 4 ; j++ ) {
+ *q++ = charz[(bv >> 18) & 0x3f];
+ bv <<= 6;
+ }
+ }
+ *--q = '\0'; /* The last character is not significant */
+ return output;
+}
+
+int main(int argc, char** argv)
+{
+ int i;
+ SHA1_CTX context;
+ uint8_t digest[20], buffer[16384];
+ FILE* file;
+
+ if (argc < 2) {
+ file = stdin;
+ }
+ else {
+ if (!(file = fopen(argv[1], "rb"))) {
+ fputs("Unable to open file.", stderr);
+ return(-1);
+ }
+ }
+ SHA1Init(&context);
+ while (!feof(file)) { /* note: what if ferror(file) */
+ i = fread(buffer, 1, 16384, file);
+ SHA1Update(&context, buffer, i);
+ }
+ SHA1Final(digest, &context);
+ fclose(file);
+
+ puts(mybase64(digest));
+
+ return 0;
+}
diff --git a/usr/klibc/shared-stub.S b/usr/klibc/shared-stub.S
new file mode 100644
index 0000000..15c0f02
--- /dev/null
+++ b/usr/klibc/shared-stub.S
@@ -0,0 +1,22 @@
+#
+# This is a hack to generate the .intrp section, which then
+# ld turns into an PT_INTERP header.
+#
+# NOTE: The .interp section needs to be "a", or it doesnt work...
+#
+
+ .section ".interp","a"
+ .ascii LIBDIR
+ .ascii "/klibc-"
+ .ascii SOHASH
+ .ascii ".so"
+ .byte 0
+
+#
+# Ensure that every executable includes some static data, as
+# ELF loaders tend to assume this - see
+# <https://bugs.debian.org/919921>, <https://bugs.debian.org/1016718>.
+#
+
+ .section ".data"
+ .byte 0
diff --git a/usr/klibc/shm_open.c b/usr/klibc/shm_open.c
new file mode 100644
index 0000000..a54e246
--- /dev/null
+++ b/usr/klibc/shm_open.c
@@ -0,0 +1,23 @@
+/*
+ * shm_open.c
+ *
+ * POSIX shared memory support
+ */
+
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+int shm_open(const char *path, int oflag, mode_t mode)
+{
+ int len = strlen(path);
+ char *pathbuf = alloca(len+10);
+
+ memcpy(pathbuf, "/dev/shm/", 9);
+ memcpy(pathbuf+9, path, len+1);
+
+ return open(path, oflag, mode|O_CLOEXEC);
+}
diff --git a/usr/klibc/shm_unlink.c b/usr/klibc/shm_unlink.c
new file mode 100644
index 0000000..94a98a0
--- /dev/null
+++ b/usr/klibc/shm_unlink.c
@@ -0,0 +1,23 @@
+/*
+ * shm_unlink.c
+ *
+ * POSIX shared memory support
+ */
+
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+int shm_unlink(const char *path)
+{
+ int len = strlen(path);
+ char *pathbuf = alloca(len+10);
+
+ memcpy(pathbuf, "/dev/shm/", 9);
+ memcpy(pathbuf+9, path, len+1);
+
+ return unlink(path);
+}
diff --git a/usr/klibc/sigabbrev.c b/usr/klibc/sigabbrev.c
new file mode 100644
index 0000000..21a799c
--- /dev/null
+++ b/usr/klibc/sigabbrev.c
@@ -0,0 +1,121 @@
+/*
+ * sigabbrev.h
+ *
+ * Construct the abbreviated signal list
+ */
+
+#include <signal.h>
+#include <unistd.h>
+
+const char *const sys_sigabbrev[NSIG] = {
+#ifdef SIGABRT
+ [SIGABRT] = "ABRT",
+#endif
+#ifdef SIGALRM
+ [SIGALRM] = "ALRM",
+#endif
+#ifdef SIGBUS
+ [SIGBUS] = "BUS",
+#endif
+#ifdef SIGCHLD
+ [SIGCHLD] = "CHLD",
+#endif
+#if defined(SIGCLD) && (SIGCHLD != SIGCLD)
+ [SIGCLD] = "CLD",
+#endif
+#ifdef SIGEMT
+ [SIGEMT] = "EMT",
+#endif
+#ifdef SIGFPE
+ [SIGFPE] = "FPE",
+#endif
+#ifdef SIGHUP
+ [SIGHUP] = "HUP",
+#endif
+#ifdef SIGILL
+ [SIGILL] = "ILL",
+#endif
+ /* SIGINFO == SIGPWR */
+#ifdef SIGINT
+ [SIGINT] = "INT",
+#endif
+#ifdef SIGIO
+ [SIGIO] = "IO",
+#endif
+#if defined(SIGIOT) && (SIGIOT != SIGABRT)
+ [SIGIOT] = "IOT",
+#endif
+#ifdef SIGKILL
+ [SIGKILL] = "KILL",
+#endif
+#if defined(SIGLOST) && (SIGLOST != SIGIO) && (SIGLOST != SIGPWR)
+ [SIGLOST] = "LOST",
+#endif
+#ifdef SIGPIPE
+ [SIGPIPE] = "PIPE",
+#endif
+#if defined(SIGPOLL) && (SIGPOLL != SIGIO)
+ [SIGPOLL] = "POLL",
+#endif
+#ifdef SIGPROF
+ [SIGPROF] = "PROF",
+#endif
+#ifdef SIGPWR
+ [SIGPWR] = "PWR",
+#endif
+#ifdef SIGQUIT
+ [SIGQUIT] = "QUIT",
+#endif
+ /* SIGRESERVE == SIGUNUSED */
+#ifdef SIGSEGV
+ [SIGSEGV] = "SEGV",
+#endif
+#ifdef SIGSTKFLT
+ [SIGSTKFLT] = "STKFLT",
+#endif
+#ifdef SIGSTOP
+ [SIGSTOP] = "STOP",
+#endif
+#ifdef SIGSYS
+ [SIGSYS] = "SYS",
+#endif
+#ifdef SIGTERM
+ [SIGTERM] = "TERM",
+#endif
+#ifdef SIGTSTP
+ [SIGTSTP] = "TSTP",
+#endif
+#ifdef SIGTTIN
+ [SIGTTIN] = "TTIN",
+#endif
+#ifdef SIGTTOU
+ [SIGTTOU] = "TTOU",
+#endif
+#ifdef SIGURG
+ [SIGURG] = "URG",
+#endif
+#ifdef SIGUSR1
+ [SIGUSR1] = "USR1",
+#endif
+#ifdef SIGUSR2
+ [SIGUSR2] = "USR2",
+#endif
+#ifdef SIGVTALRM
+ [SIGVTALRM] = "VTALRM",
+#endif
+#ifdef SIGWINCH
+ [SIGWINCH] = "WINCH",
+#endif
+#ifdef SIGXCPU
+ [SIGXCPU] = "XCPU",
+#endif
+#ifdef SIGXFSZ
+ [SIGXFSZ] = "XFSZ",
+#endif
+#ifdef SIGTRAP
+ [SIGTRAP] = "TRAP",
+#endif
+#ifdef SIGCONT
+ [SIGCONT] = "CONT",
+#endif
+};
diff --git a/usr/klibc/sigaction.c b/usr/klibc/sigaction.c
new file mode 100644
index 0000000..9481750
--- /dev/null
+++ b/usr/klibc/sigaction.c
@@ -0,0 +1,61 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern void __sigreturn(void);
+
+#if _KLIBC_NEEDS_SIGACTION_FIXUP
+typedef struct sigaction *act_type;
+#else
+typedef const struct sigaction *act_type;
+#endif
+
+__extern int __rt_sigaction(int, act_type, struct sigaction *, size_t);
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+ unsigned int needed_flags = 0
+#if _KLIBC_NEEDS_SA_RESTORER
+ | SA_RESTORER
+#endif
+#if _KLIBC_NEEDS_SA_SIGINFO
+ | SA_SIGINFO
+#endif
+ ;
+ struct sigaction sa;
+ int rv;
+
+ if (act &&
+ ((act->sa_flags & needed_flags) != needed_flags ||
+ _KLIBC_NEEDS_SIGACTION_FIXUP)) {
+ sa = *act;
+ sa.sa_flags |= needed_flags;
+#if _KLIBC_NEEDS_SA_RESTORER
+ if (!(act->sa_flags & SA_RESTORER))
+ sa.sa_restorer = &__sigreturn;
+#endif
+ act = &sa;
+ }
+
+ /* Check that we have the right signal API definitions */
+ (void)sizeof(char[_NSIG >= 64 ? 1 : -1]);
+ (void)sizeof(char[sizeof(sigset_t) * 8 >= _NSIG ? 1 : -1]);
+ (void)sizeof(char[offsetof(struct sigaction, sa_mask)
+ + sizeof(sigset_t) == sizeof(struct sigaction)
+ ? 1 : -1]);
+
+ rv = __rt_sigaction(sig, (act_type)act, oact, sizeof(sigset_t));
+
+#if _KLIBC_NEEDS_SA_RESTORER
+ if (oact && (oact->sa_restorer == &__sigreturn)) {
+ oact->sa_flags &= ~SA_RESTORER;
+ }
+#endif
+
+ return rv;
+}
diff --git a/usr/klibc/siglist.c b/usr/klibc/siglist.c
new file mode 100644
index 0000000..d690049
--- /dev/null
+++ b/usr/klibc/siglist.c
@@ -0,0 +1,121 @@
+/*
+ * siglist.h
+ *
+ * Construct the signal list
+ */
+
+#include <signal.h>
+#include <unistd.h>
+
+const char *const sys_siglist[NSIG] = {
+#ifdef SIGABRT
+ [SIGABRT] = "Aborted",
+#endif
+#ifdef SIGALRM
+ [SIGALRM] = "Alarm clock",
+#endif
+#ifdef SIGBUS
+ [SIGBUS] = "Bus error",
+#endif
+#ifdef SIGCHLD
+ [SIGCHLD] = "Child exited",
+#endif
+#if defined(SIGCLD) && (SIGCHLD != SIGCLD)
+ [SIGCLD] = "Child exited",
+#endif
+#ifdef SIGEMT
+ [SIGEMT] = "Emulation trap",
+#endif
+#ifdef SIGFPE
+ [SIGFPE] = "Floating point exception",
+#endif
+#ifdef SIGHUP
+ [SIGHUP] = "Hangup",
+#endif
+#ifdef SIGILL
+ [SIGILL] = "Illegal instruction",
+#endif
+ /* SIGINFO == SIGPWR */
+#ifdef SIGINT
+ [SIGINT] = "Interrupt",
+#endif
+#ifdef SIGIO
+ [SIGIO] = "I/O possible",
+#endif
+#if defined(SIGIOT) && (SIGIOT != SIGABRT)
+ [SIGIOT] = "I/O trap",
+#endif
+#ifdef SIGKILL
+ [SIGKILL] = "Killed",
+#endif
+#if defined(SIGLOST) && (SIGLOST != SIGIO) && (SIGLOST != SIGPWR)
+ [SIGLOST] = "Lock lost",
+#endif
+#ifdef SIGPIPE
+ [SIGPIPE] = "Broken pipe",
+#endif
+#if defined(SIGPOLL) && (SIGPOLL != SIGIO)
+ [SIGPOLL] = "Pollable event",
+#endif
+#ifdef SIGPROF
+ [SIGPROF] = "Profiling timer expired",
+#endif
+#ifdef SIGPWR
+ [SIGPWR] = "Power failure",
+#endif
+#ifdef SIGQUIT
+ [SIGQUIT] = "Quit",
+#endif
+ /* SIGRESERVE == SIGUNUSED */
+#ifdef SIGSEGV
+ [SIGSEGV] = "Segment violation",
+#endif
+#ifdef SIGSTKFLT
+ [SIGSTKFLT] = "Stack fault",
+#endif
+#ifdef SIGSTOP
+ [SIGSTOP] = "Stopped (signal)",
+#endif
+#ifdef SIGSYS
+ [SIGSYS] = "Bad system call",
+#endif
+#ifdef SIGTERM
+ [SIGTERM] = "Terminated",
+#endif
+#ifdef SIGTSTP
+ [SIGTSTP] = "Stopped",
+#endif
+#ifdef SIGTTIN
+ [SIGTTIN] = "Stopped (tty input)",
+#endif
+#ifdef SIGTTOU
+ [SIGTTOU] = "Stopped (tty output)",
+#endif
+#ifdef SIGURG
+ [SIGURG] = "Urgent I/O condition",
+#endif
+#ifdef SIGUSR1
+ [SIGUSR1] = "User signal 1",
+#endif
+#ifdef SIGUSR2
+ [SIGUSR2] = "User signal 2",
+#endif
+#ifdef SIGVTALRM
+ [SIGVTALRM] = "Virtual timer expired",
+#endif
+#ifdef SIGWINCH
+ [SIGWINCH] = "Window size changed",
+#endif
+#ifdef SIGXCPU
+ [SIGXCPU] = "CPU time limit exceeded",
+#endif
+#ifdef SIGXFSZ
+ [SIGXFSZ] = "File size limit exceeded",
+#endif
+#ifdef SIGTRAP
+ [SIGTRAP] = "Trace/breakpoint trap",
+#endif
+#ifdef SIGCONT
+ [SIGCONT] = "Continue",
+#endif
+};
diff --git a/usr/klibc/siglongjmp.c b/usr/klibc/siglongjmp.c
new file mode 100644
index 0000000..45f4e40
--- /dev/null
+++ b/usr/klibc/siglongjmp.c
@@ -0,0 +1,16 @@
+/*
+ * siglongjmp.c
+ *
+ * sigsetjmp() is a macro, by necessity (it's either that or write
+ * it in assembly), but siglongjmp() is a normal function.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+
+__noreturn siglongjmp(sigjmp_buf buf, int retval)
+{
+ if (buf->__sigs_saved)
+ sigprocmask(SIG_SETMASK, &buf->__sigs, NULL);
+ longjmp(buf->__jmpbuf, retval);
+}
diff --git a/usr/klibc/sigpending.c b/usr/klibc/sigpending.c
new file mode 100644
index 0000000..b6c50b8
--- /dev/null
+++ b/usr/klibc/sigpending.c
@@ -0,0 +1,14 @@
+/*
+ * sigpending.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern int __rt_sigpending(sigset_t *, size_t);
+
+int sigpending(sigset_t * set)
+{
+ return __rt_sigpending(set, sizeof(sigset_t));
+}
diff --git a/usr/klibc/sigprocmask.c b/usr/klibc/sigprocmask.c
new file mode 100644
index 0000000..5a5f4ae
--- /dev/null
+++ b/usr/klibc/sigprocmask.c
@@ -0,0 +1,14 @@
+/*
+ * sigprocmask.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
+
+int sigprocmask(int how, const sigset_t * set, sigset_t * oset)
+{
+ return __rt_sigprocmask(how, set, oset, sizeof(sigset_t));
+}
diff --git a/usr/klibc/sigsuspend.c b/usr/klibc/sigsuspend.c
new file mode 100644
index 0000000..120a00a
--- /dev/null
+++ b/usr/klibc/sigsuspend.c
@@ -0,0 +1,15 @@
+/*
+ * sigsuspend.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+#include <klibc/havesyscall.h>
+
+__extern int __rt_sigsuspend(const sigset_t *, size_t);
+
+int sigsuspend(const sigset_t * mask)
+{
+ return __rt_sigsuspend(mask, sizeof *mask);
+}
diff --git a/usr/klibc/sleep.c b/usr/klibc/sleep.c
new file mode 100644
index 0000000..47dfd29
--- /dev/null
+++ b/usr/klibc/sleep.c
@@ -0,0 +1,22 @@
+/*
+ * sleep.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+unsigned int sleep(unsigned int seconds)
+{
+ struct timespec ts;
+
+ ts.tv_sec = seconds;
+ ts.tv_nsec = 0;
+ if (!nanosleep(&ts, &ts))
+ return 0;
+ else if (errno == EINTR)
+ return ts.tv_sec;
+ else
+ return -1;
+}
diff --git a/usr/klibc/snprintf.c b/usr/klibc/snprintf.c
new file mode 100644
index 0000000..713b3cd
--- /dev/null
+++ b/usr/klibc/snprintf.c
@@ -0,0 +1,16 @@
+/*
+ * snprintf.c
+ */
+
+#include <stdio.h>
+
+int snprintf(char *buffer, size_t n, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsnprintf(buffer, n, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/usr/klibc/socketcalls.pl b/usr/klibc/socketcalls.pl
new file mode 100644
index 0000000..70ded0b
--- /dev/null
+++ b/usr/klibc/socketcalls.pl
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) ? !$v : 0;
+
+@args = ();
+for $arg ( @ARGV ) {
+ if ( $arg =~ /^-/ ) {
+ if ( $arg eq '-q' ) {
+ $quiet = 1;
+ } else {
+ die "$0: Unknown option: $arg\n";
+ }
+ } else {
+ push(@args, $arg);
+ }
+}
+($file, $arch, $outputdir) = @args;
+
+if (!open(FILE, "< $file")) {
+ die "$file: $!\n";
+}
+
+print "socketcall-objs := ";
+while ( defined($line = <FILE>) ) {
+ chomp $line;
+ $line =~ s/\s*(|\#.*|\/\/.*)$//; # Strip comments and trailing blanks
+ next unless $line;
+
+ if ( $line =~ /^\s*\<\?\>\s*(.*)\s+([_a-zA-Z][_a-zA-Z0-9]+)\s*\((.*)\)\s*\;$/ ) {
+ $type = $1;
+ $name = $2;
+ $argv = $3;
+
+ @args = split(/\s*\,\s*/, $argv);
+ @cargs = ();
+
+ $i = 0;
+ for $arg ( @args ) {
+ push(@cargs, "$arg a".$i++);
+ }
+ $nargs = $i;
+ print " \\\n\t${name}.o";
+
+ open(OUT, "> ${outputdir}/${name}.c")
+ or die "$0: Cannot open ${outputdir}/${name}.c\n";
+
+ print OUT "#include \"socketcommon.h\"\n";
+ print OUT "\n";
+ print OUT "#if _KLIBC_SYS_SOCKETCALL\n";
+ print OUT "# define DO_THIS_SOCKETCALL\n";
+ print OUT "#else\n";
+ print OUT "# if !defined(__NR_${name})";
+ if ($name eq 'accept') {
+ print OUT " && !defined(__NR_accept4)";
+ }
+ print OUT "\n# define DO_THIS_SOCKETCALL\n";
+ print OUT "# endif\n";
+ print OUT "#endif\n\n";
+
+ print OUT "#if defined(DO_THIS_SOCKETCALL) && defined(SYS_\U${name}\E)\n\n";
+
+ print OUT "extern long __socketcall(int, const unsigned long *);\n\n";
+
+ print OUT "$type ${name}(", join(', ', @cargs), ")\n";
+ print OUT "{\n";
+ print OUT " unsigned long args[$nargs];\n";
+ for ( $i = 0 ; $i < $nargs ; $i++ ) {
+ print OUT " args[$i] = (unsigned long)a$i;\n";
+ }
+ print OUT " return ($type) __socketcall(SYS_\U${name}\E, args);\n";
+ print OUT "}\n\n";
+
+ print OUT "#endif\n";
+
+ close(OUT);
+ } else {
+ die "$file:$.: Could not parse input\n";
+ }
+}
+
+print "\n";
diff --git a/usr/klibc/socketcalls/.gitignore b/usr/klibc/socketcalls/.gitignore
new file mode 100644
index 0000000..67da0d1
--- /dev/null
+++ b/usr/klibc/socketcalls/.gitignore
@@ -0,0 +1,4 @@
+*.S
+*.c
+SOCKETCALLS.i
+socketcalls.mk
diff --git a/usr/klibc/socketcalls/Kbuild b/usr/klibc/socketcalls/Kbuild
new file mode 100644
index 0000000..a974a88
--- /dev/null
+++ b/usr/klibc/socketcalls/Kbuild
@@ -0,0 +1,52 @@
+#
+# Generate socket calls based on SOCKETCALLS.def
+#
+
+# Include automatically generated Makefile fragment.
+# It contains definition of socketcall-objs specifying name of all .o files
+ifeq ($(clean),)
+-include $(obj)/socketcalls.mk
+endif
+
+# Listing of all .o files
+always := klib.list
+
+#####
+# Generate socket calls stubs
+# Based on input from SOCKETCALLS.def generate socket call stubs
+targets := klib.list
+targets += socketcalls.mk
+targets += SOCKETCALLS.i
+targets += $(socketcall-objs)
+clean-files += *.S *.c *.o *.list
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src)
+
+quiet_cmd_makelist = LIST $@
+ cmd_makelist = echo '$(filter-out FORCE,$^)' > $@
+
+# Create list of all files
+$(obj)/klib.list: $(call objectify,$(socketcall-objs)) FORCE
+ $(call if_changed,makelist)
+
+# Generate assembler file (.i)
+# We pass -ansi to keep cpp from define e.g. "i386" as well as "__i386__"
+quiet_cmd_socketcall.i = GEN $@
+ cmd_socketcall.i = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__ \
+ -ansi -x c -E -o $@ $<
+$(obj)/SOCKETCALLS.i: $(KLIBCSRC)/SOCKETCALLS.def FORCE
+ $(call if_changed_dep,socketcall.i)
+
+# Generate socketcall stubs
+quiet_cmd_socketcalls = GEN $@
+ cmd_socketcalls = $(PERL) $(srctree)/$(KLIBCSRC)/socketcalls.pl \
+ $(obj)/SOCKETCALLS.i \
+ $(KLIBCARCH) $(obj) > $@ \
+ || ( rm -f $@ ; exit 1 )
+
+$(obj)/socketcalls.mk: $(srctree)/$(KLIBCSRC)/socketcalls.pl \
+ $(obj)/SOCKETCALLS.i \
+ $(src)/socketcommon.h
+ $(call cmd,socketcalls)
+
+PHONY += FORCE
diff --git a/usr/klibc/socketcalls/socketcommon.h b/usr/klibc/socketcalls/socketcommon.h
new file mode 100644
index 0000000..7fdd547
--- /dev/null
+++ b/usr/klibc/socketcalls/socketcommon.h
@@ -0,0 +1,15 @@
+/*
+ * socketcommon.h
+ *
+ * Common header file for socketcall stubs
+ */
+
+#define __IN_SYS_COMMON
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <linux/net.h>
diff --git a/usr/klibc/sprintf.c b/usr/klibc/sprintf.c
new file mode 100644
index 0000000..c6d8758
--- /dev/null
+++ b/usr/klibc/sprintf.c
@@ -0,0 +1,18 @@
+/*
+ * sprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int sprintf(char *buffer, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsnprintf(buffer, ~(size_t) 0, format, ap);
+ va_end(ap);
+
+ return rv;
+}
diff --git a/usr/klibc/srand48.c b/usr/klibc/srand48.c
new file mode 100644
index 0000000..e1c9567
--- /dev/null
+++ b/usr/klibc/srand48.c
@@ -0,0 +1,15 @@
+/*
+ * srand48.c
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+unsigned short __rand48_seed[3]; /* Common with mrand48.c, lrand48.c */
+
+void srand48(long seedval)
+{
+ __rand48_seed[0] = 0x330e;
+ __rand48_seed[1] = (unsigned short)seedval;
+ __rand48_seed[2] = (unsigned short)((uint32_t) seedval >> 16);
+}
diff --git a/usr/klibc/sscanf.c b/usr/klibc/sscanf.c
new file mode 100644
index 0000000..f53b276
--- /dev/null
+++ b/usr/klibc/sscanf.c
@@ -0,0 +1,17 @@
+/*
+ * sscanf()
+ */
+
+#include <stdio.h>
+
+int sscanf(const char *str, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsscanf(str, format, ap);
+ va_end(ap);
+
+ return rv;
+}
diff --git a/usr/klibc/stat.c b/usr/klibc/stat.c
new file mode 100644
index 0000000..673fb06
--- /dev/null
+++ b/usr/klibc/stat.c
@@ -0,0 +1,10 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+int stat(const char *path, struct stat *buf)
+{
+ return fstatat(AT_FDCWD, path, buf, 0);
+}
diff --git a/usr/klibc/statfs.c b/usr/klibc/statfs.c
new file mode 100644
index 0000000..b8b8700
--- /dev/null
+++ b/usr/klibc/statfs.c
@@ -0,0 +1,19 @@
+/*
+ * statfs.c
+ *
+ * On architectures which do statfs64, wrap the system call
+ */
+
+#include <sys/syscall.h>
+#include <sys/vfs.h>
+
+#ifdef __NR_statfs64
+
+extern int __statfs64(const char *, size_t, struct statfs *);
+
+int statfs(const char *path, struct statfs *buf)
+{
+ return __statfs64(path, sizeof *buf, buf);
+}
+
+#endif
diff --git a/usr/klibc/stdio/clearerr.c b/usr/klibc/stdio/clearerr.c
new file mode 100644
index 0000000..ebdd22d
--- /dev/null
+++ b/usr/klibc/stdio/clearerr.c
@@ -0,0 +1,9 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+void clearerr(FILE *__f)
+{
+ __f->_IO_error = 0;
+ __f->_IO_eof = 0;
+}
+__ALIAS(void, clearerr_unlocked, (FILE *), clearerr)
diff --git a/usr/klibc/stdio/fclose.c b/usr/klibc/stdio/fclose.c
new file mode 100644
index 0000000..756de43
--- /dev/null
+++ b/usr/klibc/stdio/fclose.c
@@ -0,0 +1,22 @@
+/*
+ * fclose.c
+ */
+
+#include "stdioint.h"
+
+int fclose(FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ int rv;
+
+ fflush(file);
+
+ rv = close(f->pub._IO_fileno);
+
+ /* Remove from linked list */
+ f->next->prev = f->prev;
+ f->prev->next = f->next;
+
+ free(f);
+ return rv;
+}
diff --git a/usr/klibc/stdio/fdopen.c b/usr/klibc/stdio/fdopen.c
new file mode 100644
index 0000000..cdc35cc
--- /dev/null
+++ b/usr/klibc/stdio/fdopen.c
@@ -0,0 +1,57 @@
+/*
+ * fdopen.c
+ *
+ * Common code between fopen(), fdopen() and the standard descriptors.
+ */
+
+#include "stdioint.h"
+
+FILE *stdin, *stdout, *stderr;
+
+/* Doubly-linked list of all stdio structures */
+struct _IO_file_pvt __stdio_headnode =
+{
+ .prev = &__stdio_headnode,
+ .next = &__stdio_headnode,
+};
+
+FILE *fdopen(int fd, const char *mode)
+{
+ struct _IO_file_pvt *f;
+ const size_t bufoffs =
+ (sizeof *f + 4*sizeof(void *) - 1) &
+ ~(4*sizeof(void *) - 1);
+
+ (void)mode;
+
+ f = zalloc(bufoffs + BUFSIZ + _IO_UNGET_SLOP);
+ if (!f)
+ goto err;
+
+ f->data = f->buf = (char *)f + bufoffs;
+ f->pub._IO_fileno = fd;
+ f->bufsiz = BUFSIZ;
+ f->bufmode = isatty(fd) ? _IOLBF : _IOFBF;
+
+ /* Insert into linked list */
+ f->prev = &__stdio_headnode;
+ f->next = __stdio_headnode.next;
+ f->next->prev = f;
+ __stdio_headnode.next = f;
+
+ return &f->pub;
+
+err:
+ if (f)
+ free(f);
+ errno = ENOMEM;
+ return NULL;
+}
+
+void __libc_init_stdio(void)
+{
+ stdin = fdopen(0, NULL);
+ stdout = fdopen(1, NULL);
+ stderr = fdopen(2, NULL);
+ stdio_pvt(stderr)->bufmode = _IONBF;
+}
diff --git a/usr/klibc/stdio/feof.c b/usr/klibc/stdio/feof.c
new file mode 100644
index 0000000..4215c11
--- /dev/null
+++ b/usr/klibc/stdio/feof.c
@@ -0,0 +1,8 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int feof(FILE *__f)
+{
+ return __f->_IO_eof;
+}
+__ALIAS(int, feof_unlocked, (FILE *), feof)
diff --git a/usr/klibc/stdio/ferror.c b/usr/klibc/stdio/ferror.c
new file mode 100644
index 0000000..819743b
--- /dev/null
+++ b/usr/klibc/stdio/ferror.c
@@ -0,0 +1,8 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int ferror(FILE *__f)
+{
+ return __f->_IO_error;
+}
+__ALIAS(int, ferror_unlocked, (FILE *), ferror)
diff --git a/usr/klibc/stdio/fflush.c b/usr/klibc/stdio/fflush.c
new file mode 100644
index 0000000..6ac5cf5
--- /dev/null
+++ b/usr/klibc/stdio/fflush.c
@@ -0,0 +1,60 @@
+/*
+ * fflush.c
+ */
+
+#include "stdioint.h"
+
+int __fflush(struct _IO_file_pvt *f)
+{
+ ssize_t rv;
+ char *p;
+
+ /*
+ * Flush any unused input data. If there is input data, there
+ * won't be any output data.
+ */
+ if (__unlikely(f->ibytes))
+ return fseek(&f->pub, 0, SEEK_CUR);
+
+ p = f->buf;
+ while (f->obytes) {
+ rv = write(f->pub._IO_fileno, p, f->obytes);
+ if (rv == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ f->pub._IO_error = true;
+ return EOF;
+ } else if (rv == 0) {
+ /* EOF on output? */
+ f->pub._IO_eof = true;
+ return EOF;
+ }
+
+ p += rv;
+ f->obytes -= rv;
+ }
+
+ return 0;
+}
+
+int fflush(FILE *file)
+{
+ struct _IO_file_pvt *f;
+
+ if (__likely(file)) {
+ f = stdio_pvt(file);
+ return __fflush(f);
+ } else {
+ int err = 0;
+
+ for (f = __stdio_headnode.next;
+ f != &__stdio_headnode;
+ f = f->next) {
+ if (f->obytes)
+ err |= __fflush(f);
+ }
+ return err;
+ }
+}
+__ALIAS(int, fflush_unlocked, (FILE *), fflush)
+
diff --git a/usr/klibc/stdio/fgetc.c b/usr/klibc/stdio/fgetc.c
new file mode 100644
index 0000000..5d1fc06
--- /dev/null
+++ b/usr/klibc/stdio/fgetc.c
@@ -0,0 +1,19 @@
+/*
+ * fgetc.c
+ */
+
+#include "stdioint.h"
+
+int fgetc(FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ unsigned char ch;
+
+ if (__likely(f->ibytes)) {
+ f->ibytes--;
+ return (unsigned char) *f->data++;
+ } else {
+ return _fread(&ch, 1, file) == 1 ? ch : EOF;
+ }
+}
+__ALIAS(int, fgetc_unlocked, (FILE *), fgetc)
diff --git a/usr/klibc/stdio/fileno.c b/usr/klibc/stdio/fileno.c
new file mode 100644
index 0000000..16c15dd
--- /dev/null
+++ b/usr/klibc/stdio/fileno.c
@@ -0,0 +1,8 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int fileno(FILE *__f)
+{
+ return __f->_IO_fileno;
+}
+__ALIAS(int, fileno_unlocked, (FILE *), fileno)
diff --git a/usr/klibc/stdio/fopen.c b/usr/klibc/stdio/fopen.c
new file mode 100644
index 0000000..cf098df
--- /dev/null
+++ b/usr/klibc/stdio/fopen.c
@@ -0,0 +1,59 @@
+/*
+ * fopen.c
+ */
+
+#include "stdioint.h"
+
+static int __parse_open_mode(const char *mode)
+{
+ int rwflags = O_RDONLY;
+ int crflags = 0;
+ int eflags = 0;
+
+ while (*mode) {
+ switch (*mode++) {
+ case 'r':
+ rwflags = O_RDONLY;
+ crflags = 0;
+ break;
+ case 'w':
+ rwflags = O_WRONLY;
+ crflags = O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ rwflags = O_WRONLY;
+ crflags = O_CREAT | O_APPEND;
+ break;
+ case 'e':
+ eflags |= O_CLOEXEC;
+ break;
+ case 'x':
+ eflags |= O_EXCL;
+ break;
+ case '+':
+ rwflags = O_RDWR;
+ break;
+ }
+ }
+
+ return rwflags | crflags | eflags;
+}
+
+FILE *fopen(const char *file, const char *mode)
+{
+ int flags = __parse_open_mode(mode);
+ int fd, err;
+ FILE *f;
+
+ fd = open(file, flags, 0666);
+ if (fd < 0)
+ return NULL;
+
+ f = fdopen(fd, mode);
+ if (!f) {
+ err = errno;
+ close(fd);
+ errno = err;
+ }
+ return f;
+}
diff --git a/usr/klibc/stdio/fread.c b/usr/klibc/stdio/fread.c
new file mode 100644
index 0000000..b099426
--- /dev/null
+++ b/usr/klibc/stdio/fread.c
@@ -0,0 +1,79 @@
+/*
+ * fread.c
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include "stdioint.h"
+
+size_t _fread(void *buf, size_t count, FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ size_t bytes = 0;
+ size_t nb;
+ char *p = buf;
+ char *rdptr;
+ ssize_t rv;
+ bool bypass;
+
+ if (!count)
+ return 0;
+
+ if (f->obytes) /* User error! */
+ __fflush(f);
+
+ while (count) {
+ while (f->ibytes == 0) {
+ /*
+ * The buffer is empty, we have to read
+ */
+ bypass = (count >= f->bufsiz);
+ if (bypass) {
+ /* Large read, bypass buffer */
+ rdptr = p;
+ nb = count;
+ } else {
+ rdptr = f->buf + _IO_UNGET_SLOP;
+ nb = f->bufsiz;
+ }
+
+ rv = read(f->pub._IO_fileno, rdptr, nb);
+ if (rv == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ f->pub._IO_error = true;
+ return bytes;
+ } else if (rv == 0) {
+ f->pub._IO_eof = true;
+ return bytes;
+
+
+ }
+
+ if (bypass) {
+ p += rv;
+ bytes += rv;
+ count -= rv;
+ } else {
+ f->ibytes = rv;
+ f->data = rdptr;
+ }
+
+ if (!count)
+ return bytes;
+ }
+
+ /* If we get here, the buffer is non-empty */
+ nb = f->ibytes;
+ nb = (count < nb) ? count : nb;
+ if (nb) {
+ memcpy(p, f->data, nb);
+ p += nb;
+ bytes += nb;
+ count -= nb;
+ f->data += nb;
+ f->ibytes -= nb;
+ }
+ }
+ return bytes;
+}
diff --git a/usr/klibc/stdio/fseek.c b/usr/klibc/stdio/fseek.c
new file mode 100644
index 0000000..e35f85e
--- /dev/null
+++ b/usr/klibc/stdio/fseek.c
@@ -0,0 +1,28 @@
+/*
+ * fseek.c
+ */
+
+#include "stdioint.h"
+
+__extern int fseek(FILE *file, off_t where, int whence)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ off_t rv;
+
+ if (f->obytes)
+ if (__fflush(f))
+ return -1;
+
+ if (whence == SEEK_CUR)
+ where -= f->ibytes;
+
+ rv = lseek(f->pub._IO_fileno, where, whence);
+ if (__likely(rv >= 0)) {
+ f->pub._IO_eof = false;
+ f->ibytes = 0;
+ return 0;
+ } else {
+ f->pub._IO_error = true;
+ return -1;
+ }
+}
diff --git a/usr/klibc/stdio/ftell.c b/usr/klibc/stdio/ftell.c
new file mode 100644
index 0000000..cb1202d
--- /dev/null
+++ b/usr/klibc/stdio/ftell.c
@@ -0,0 +1,12 @@
+#include "stdioint.h"
+
+off_t ftell(FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ off_t pos = lseek(f->pub._IO_fileno, 0, SEEK_CUR);
+
+ if (pos >= 0)
+ pos += (int)f->obytes - (int)f->ibytes;
+
+ return pos;
+}
diff --git a/usr/klibc/stdio/fwrite.c b/usr/klibc/stdio/fwrite.c
new file mode 100644
index 0000000..9f32ae4
--- /dev/null
+++ b/usr/klibc/stdio/fwrite.c
@@ -0,0 +1,97 @@
+/*
+ * fwrite.c
+ */
+
+#include <string.h>
+#include "stdioint.h"
+
+static size_t fwrite_noflush(const void *buf, size_t count,
+ struct _IO_file_pvt *f)
+{
+ size_t bytes = 0;
+ size_t nb;
+ const char *p = buf;
+ ssize_t rv;
+
+ while (count) {
+ if (f->ibytes || f->obytes >= f->bufsiz ||
+ (f->obytes && count >= f->bufsiz))
+ if (__fflush(f))
+ break;
+
+ if (count >= f->bufsiz) {
+ /*
+ * The write is large, so bypass
+ * buffering entirely.
+ */
+ rv = write(f->pub._IO_fileno, p, count);
+ if (rv == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ f->pub._IO_error = true;
+ break;
+ } else if (rv == 0) {
+ /* EOF on output? */
+ f->pub._IO_eof = true;
+ break;
+ }
+
+ p += rv;
+ bytes += rv;
+ count -= rv;
+ } else {
+ nb = f->bufsiz - f->obytes;
+ nb = (count < nb) ? count : nb;
+ if (nb) {
+ memcpy(f->buf+f->obytes, p, nb);
+ p += nb;
+ f->obytes += nb;
+ count -= nb;
+ bytes += nb;
+ }
+ }
+ }
+ return bytes;
+}
+
+size_t _fwrite(const void *buf, size_t count, FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+ size_t bytes = 0;
+ size_t pf_len, pu_len;
+ const char *p = buf;
+ const char *q;
+
+ /* We divide the data into two chunks, flushed (pf)
+ and unflushed (pu) depending on buffering mode
+ and contents. */
+
+ switch (f->bufmode) {
+ case _IOFBF:
+ pf_len = 0;
+ break;
+
+ case _IOLBF:
+ q = memrchr(p, '\n', count);
+ pf_len = q ? q - p + 1 : 0;
+ break;
+
+ case _IONBF:
+ default:
+ pf_len = count;
+ break;
+ }
+
+ if (pf_len) {
+ bytes = fwrite_noflush(p, pf_len, f);
+ p += bytes;
+ if (__fflush(f) || bytes != pf_len)
+ return bytes;
+ }
+
+ pu_len = count - pf_len;
+ if (pu_len)
+ bytes += fwrite_noflush(p, pu_len, f);
+
+ return bytes;
+}
diff --git a/usr/klibc/stdio/rewind.c b/usr/klibc/stdio/rewind.c
new file mode 100644
index 0000000..fb7cd5a
--- /dev/null
+++ b/usr/klibc/stdio/rewind.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include <stdbool.h>
+
+void rewind(FILE *f)
+{
+ if (!fseek(f, 0, SEEK_SET))
+ f->_IO_error = false;
+}
diff --git a/usr/klibc/stdio/stdioint.h b/usr/klibc/stdio/stdioint.h
new file mode 100644
index 0000000..724c657
--- /dev/null
+++ b/usr/klibc/stdio/stdioint.h
@@ -0,0 +1,38 @@
+/*
+ * stdioint.h
+ *
+ * stdio internals
+ */
+
+#ifndef USR_KLIBC_STDIO_STDIOINT_H
+#define USR_KLIBC_STDIO_STDIOINT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Actual FILE structure */
+struct _IO_file_pvt {
+ struct _IO_file pub; /* Data exported to inlines */
+ struct _IO_file_pvt *prev, *next;
+ char *buf; /* Buffer */
+ char *data; /* Location of input data in buffer */
+ unsigned int ibytes; /* Input data bytes in buffer */
+ unsigned int obytes; /* Output data bytes in buffer */
+ unsigned int bufsiz; /* Total size of buffer */
+ enum _IO_bufmode bufmode; /* Type of buffering */
+};
+
+#define stdio_pvt(x) container_of(x, struct _IO_file_pvt, pub)
+
+/* Assign this much extra to the input buffer in case of ungetc() */
+#define _IO_UNGET_SLOP 32
+
+__extern int __fflush(struct _IO_file_pvt *);
+
+__extern struct _IO_file_pvt __stdio_headnode;
+
+#endif /* USR_KLIBC_STDIO_STDIOINT_H */
diff --git a/usr/klibc/stdio/ungetc.c b/usr/klibc/stdio/ungetc.c
new file mode 100644
index 0000000..fe328ac
--- /dev/null
+++ b/usr/klibc/stdio/ungetc.c
@@ -0,0 +1,17 @@
+/*
+ * ungetc.c
+ */
+
+#include "stdioint.h"
+
+int ungetc(int c, FILE *file)
+{
+ struct _IO_file_pvt *f = stdio_pvt(file);
+
+ if (f->obytes || f->data <= f->buf)
+ return EOF;
+
+ *(--f->data) = c;
+ f->ibytes++;
+ return c;
+}
diff --git a/usr/klibc/strcasecmp.c b/usr/klibc/strcasecmp.c
new file mode 100644
index 0000000..ee1f28b
--- /dev/null
+++ b/usr/klibc/strcasecmp.c
@@ -0,0 +1,24 @@
+/*
+ * strcasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
+ unsigned char ch;
+ int d = 0;
+
+ while (1) {
+ /* toupper() expects an unsigned char (implicitly cast to int)
+ as input, and returns an int, which is exactly what we want. */
+ d = toupper(ch = *c1++) - toupper(*c2++);
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
diff --git a/usr/klibc/strcat.c b/usr/klibc/strcat.c
new file mode 100644
index 0000000..6c5b673
--- /dev/null
+++ b/usr/klibc/strcat.c
@@ -0,0 +1,11 @@
+/*
+ * strcat.c
+ */
+
+#include <string.h>
+
+char *strcat(char *dst, const char *src)
+{
+ strcpy(strchr(dst, '\0'), src);
+ return dst;
+}
diff --git a/usr/klibc/strchr.c b/usr/klibc/strchr.c
new file mode 100644
index 0000000..6040cc4
--- /dev/null
+++ b/usr/klibc/strchr.c
@@ -0,0 +1,19 @@
+/*
+ * strchr.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strchr(const char *s, int c)
+{
+ while (*s != (char)c) {
+ if (!*s)
+ return NULL;
+ s++;
+ }
+
+ return (char *)s;
+}
+
+__ALIAS(char *, index, (const char *, int), strchr)
diff --git a/usr/klibc/strcmp.c b/usr/klibc/strcmp.c
new file mode 100644
index 0000000..3ab9f5a
--- /dev/null
+++ b/usr/klibc/strcmp.c
@@ -0,0 +1,21 @@
+/*
+ * strcmp.c
+ */
+
+#include <string.h>
+
+int strcmp(const char *s1, const char *s2)
+{
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
+ unsigned char ch;
+ int d = 0;
+
+ while (1) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
diff --git a/usr/klibc/strcpy.c b/usr/klibc/strcpy.c
new file mode 100644
index 0000000..aa656cf
--- /dev/null
+++ b/usr/klibc/strcpy.c
@@ -0,0 +1,20 @@
+/*
+ * strcpy.c
+ *
+ * strcpy()
+ */
+
+#include <string.h>
+
+char *strcpy(char *dst, const char *src)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ do {
+ *q++ = ch = *p++;
+ } while (ch);
+
+ return dst;
+}
diff --git a/usr/klibc/strcspn.c b/usr/klibc/strcspn.c
new file mode 100644
index 0000000..35fd38c
--- /dev/null
+++ b/usr/klibc/strcspn.c
@@ -0,0 +1,12 @@
+/*
+ * strcspn
+ */
+
+#include <string.h>
+
+#include "strxspn.h"
+
+size_t strcspn(const char *s, const char *reject)
+{
+ return __strxspn(s, reject, 1);
+}
diff --git a/usr/klibc/strdup.c b/usr/klibc/strdup.c
new file mode 100644
index 0000000..905b51d
--- /dev/null
+++ b/usr/klibc/strdup.c
@@ -0,0 +1,17 @@
+/*
+ * strdup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strdup(const char *s)
+{
+ int l = strlen(s) + 1;
+ char *d = malloc(l);
+
+ if (d)
+ memcpy(d, s, l);
+
+ return d;
+}
diff --git a/usr/klibc/strerror.c b/usr/klibc/strerror.c
new file mode 100644
index 0000000..fed0e49
--- /dev/null
+++ b/usr/klibc/strerror.c
@@ -0,0 +1,33 @@
+/*
+ * strerror.c
+ */
+
+#include <string.h>
+
+char *strerror(int errnum)
+{
+ static char message[32] = "error "; /* enough for error 2^63-1 */
+ char numbuf[32];
+ char *p;
+ unsigned int e = (unsigned int)errnum;
+
+#ifdef WITH_ERRLIST
+ extern const int sys_nerr;
+ extern const char *const sys_errlist[];
+
+ if (e < (unsigned int)sys_nerr && sys_errlist[e])
+ return (char *)sys_errlist[e];
+#endif
+
+ p = numbuf + sizeof numbuf;
+ *--p = '\0';
+
+ do {
+ *--p = (e % 10) + '0';
+ e /= 10;
+ } while (e);
+
+ memcpy(message + 6, p, (numbuf + sizeof numbuf) - p);
+
+ return message;
+}
diff --git a/usr/klibc/strlcat.c b/usr/klibc/strlcat.c
new file mode 100644
index 0000000..80c3375
--- /dev/null
+++ b/usr/klibc/strlcat.c
@@ -0,0 +1,31 @@
+/*
+ * strlcat.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+size_t strlcat(char *dst, const char *src, size_t size)
+{
+ size_t bytes = 0;
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while (bytes < size && *q) {
+ q++;
+ bytes++;
+ }
+ if (bytes == size)
+ return (bytes + strlen(src));
+
+ while ((ch = *p++)) {
+ if (bytes + 1 < size)
+ *q++ = ch;
+
+ bytes++;
+ }
+
+ *q = '\0';
+ return bytes;
+}
diff --git a/usr/klibc/strlcpy.c b/usr/klibc/strlcpy.c
new file mode 100644
index 0000000..51c72d8
--- /dev/null
+++ b/usr/klibc/strlcpy.c
@@ -0,0 +1,27 @@
+/*
+ * strlcpy.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+size_t strlcpy(char *dst, const char *src, size_t size)
+{
+ size_t bytes = 0;
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while ((ch = *p++)) {
+ if (bytes + 1 < size)
+ *q++ = ch;
+
+ bytes++;
+ }
+
+ /* If size == 0 there is no space for a final null... */
+ if (size)
+ *q = '\0';
+
+ return bytes;
+}
diff --git a/usr/klibc/strlen.c b/usr/klibc/strlen.c
new file mode 100644
index 0000000..86526a5
--- /dev/null
+++ b/usr/klibc/strlen.c
@@ -0,0 +1,13 @@
+/*
+ * strlen()
+ */
+
+#include <string.h>
+
+size_t strlen(const char *s)
+{
+ const char *ss = s;
+ while (*ss)
+ ss++;
+ return ss - s;
+}
diff --git a/usr/klibc/strncasecmp.c b/usr/klibc/strncasecmp.c
new file mode 100644
index 0000000..0551935
--- /dev/null
+++ b/usr/klibc/strncasecmp.c
@@ -0,0 +1,24 @@
+/*
+ * strncasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
+ unsigned char ch;
+ int d = 0;
+
+ while (n--) {
+ /* toupper() expects an unsigned char (implicitly cast to int)
+ as input, and returns an int, which is exactly what we want. */
+ d = toupper(ch = *c1++) - toupper(*c2++);
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
diff --git a/usr/klibc/strncat.c b/usr/klibc/strncat.c
new file mode 100644
index 0000000..beb026c
--- /dev/null
+++ b/usr/klibc/strncat.c
@@ -0,0 +1,22 @@
+/*
+ * strncat.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strncat(char *dst, const char *src, size_t n)
+{
+ char *q = strchr(dst, '\0');
+ const char *p = src;
+ char ch;
+
+ while (n--) {
+ *q++ = ch = *p++;
+ if (!ch)
+ return dst;
+ }
+ *q = '\0';
+
+ return dst;
+}
diff --git a/usr/klibc/strncmp.c b/usr/klibc/strncmp.c
new file mode 100644
index 0000000..5235545
--- /dev/null
+++ b/usr/klibc/strncmp.c
@@ -0,0 +1,21 @@
+/*
+ * strncmp.c
+ */
+
+#include <string.h>
+
+int strncmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
+ unsigned char ch;
+ int d = 0;
+
+ while (n--) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
diff --git a/usr/klibc/strncpy.c b/usr/klibc/strncpy.c
new file mode 100644
index 0000000..fffc118
--- /dev/null
+++ b/usr/klibc/strncpy.c
@@ -0,0 +1,24 @@
+/*
+ * strncpy.c
+ */
+
+#include <string.h>
+
+char *strncpy(char *dst, const char *src, size_t n)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ while (n) {
+ n--;
+ *q++ = ch = *p++;
+ if (!ch)
+ break;
+ }
+
+ /* The specs say strncpy() fills the entire buffer with NUL. Sigh. */
+ memset(q, 0, n);
+
+ return dst;
+}
diff --git a/usr/klibc/strndup.c b/usr/klibc/strndup.c
new file mode 100644
index 0000000..20eaa8b
--- /dev/null
+++ b/usr/klibc/strndup.c
@@ -0,0 +1,18 @@
+/*
+ * strndup.c
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strndup(const char *s, size_t n)
+{
+ size_t l = strnlen(s, n);
+ char *d = malloc(l + 1);
+ if (!d)
+ return NULL;
+
+ memcpy(d, s, l);
+ d[l] = '\0';
+ return d;
+}
diff --git a/usr/klibc/strnlen.c b/usr/klibc/strnlen.c
new file mode 100644
index 0000000..1678f4b
--- /dev/null
+++ b/usr/klibc/strnlen.c
@@ -0,0 +1,18 @@
+/*
+ * strnlen()
+ */
+
+#include <string.h>
+
+size_t strnlen(const char *s, size_t maxlen)
+{
+ const char *ss = s;
+
+ /* Important: the maxlen test must precede the reference through ss;
+ since the byte beyond the maximum may segfault */
+ while ((maxlen > 0) && *ss) {
+ ss++;
+ maxlen--;
+ }
+ return ss - s;
+}
diff --git a/usr/klibc/strntoimax.c b/usr/klibc/strntoimax.c
new file mode 100644
index 0000000..179d9e5
--- /dev/null
+++ b/usr/klibc/strntoimax.c
@@ -0,0 +1,13 @@
+/*
+ * strntoimax.c
+ *
+ * strntoimax()
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+intmax_t strntoimax(const char *nptr, char **endptr, int base, size_t n)
+{
+ return (intmax_t) strntoumax(nptr, endptr, base, n);
+}
diff --git a/usr/klibc/strntoumax.c b/usr/klibc/strntoumax.c
new file mode 100644
index 0000000..56dddad
--- /dev/null
+++ b/usr/klibc/strntoumax.c
@@ -0,0 +1,77 @@
+/*
+ * strntoumax.c
+ *
+ * The strntoumax() function and associated
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+static inline int digitval(int ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'A' && ch <= 'Z') {
+ return ch - 'A' + 10;
+ } else if (ch >= 'a' && ch <= 'z') {
+ return ch - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
+{
+ int minus = 0;
+ uintmax_t v = 0;
+ int d;
+
+ while (n && isspace((unsigned char)*nptr)) {
+ nptr++;
+ n--;
+ }
+
+ /* Single optional + or - */
+ if (n) {
+ char c = *nptr;
+ if (c == '-' || c == '+') {
+ minus = (c == '-');
+ nptr++;
+ n--;
+ }
+ }
+
+ if (base == 0) {
+ if (n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ base = 16;
+ } else if (n >= 1 && nptr[0] == '0') {
+ n--;
+ nptr++;
+ base = 8;
+ } else {
+ base = 10;
+ }
+ } else if (base == 16) {
+ if (n >= 2 && nptr[0] == '0' &&
+ (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ }
+ }
+
+ while (n && (d = digitval(*nptr)) >= 0 && d < base) {
+ v = v * base + d;
+ n--;
+ nptr++;
+ }
+
+ if (endptr)
+ *endptr = (char *)nptr;
+
+ return minus ? -v : v;
+}
diff --git a/usr/klibc/strpbrk.c b/usr/klibc/strpbrk.c
new file mode 100644
index 0000000..300dbba
--- /dev/null
+++ b/usr/klibc/strpbrk.c
@@ -0,0 +1,14 @@
+/*
+ * strpbrk
+ */
+
+#include <string.h>
+
+#include "strxspn.h"
+
+char *strpbrk(const char *s, const char *accept)
+{
+ const char *ss = s + __strxspn(s, accept, 1);
+
+ return *ss ? (char *)ss : NULL;
+}
diff --git a/usr/klibc/strrchr.c b/usr/klibc/strrchr.c
new file mode 100644
index 0000000..af68ffe
--- /dev/null
+++ b/usr/klibc/strrchr.c
@@ -0,0 +1,23 @@
+/*
+ * strrchr.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strrchr(const char *s, int c)
+{
+ const char *found = NULL;
+
+ for (;;) {
+ if (*s == (char)c)
+ found = s;
+ if (!*s)
+ break;
+ s++;
+ }
+
+ return (char *)found;
+}
+
+__ALIAS(char *, rindex, (const char *, int), strrchr)
diff --git a/usr/klibc/strsep.c b/usr/klibc/strsep.c
new file mode 100644
index 0000000..44e76bd
--- /dev/null
+++ b/usr/klibc/strsep.c
@@ -0,0 +1,21 @@
+/*
+ * strsep.c
+ */
+
+#include <string.h>
+
+char *strsep(char **stringp, const char *delim)
+{
+ char *s = *stringp;
+ char *e;
+
+ if (!s)
+ return NULL;
+
+ e = strpbrk(s, delim);
+ if (e)
+ *e++ = '\0';
+
+ *stringp = e;
+ return s;
+}
diff --git a/usr/klibc/strsignal.c b/usr/klibc/strsignal.c
new file mode 100644
index 0000000..e345e9c
--- /dev/null
+++ b/usr/klibc/strsignal.c
@@ -0,0 +1,26 @@
+/*
+ * strsignal.c
+ */
+
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+
+char *strsignal(int sig)
+{
+ static char buf[64];
+
+ if ((unsigned)sig < _NSIG && sys_siglist[sig])
+ return (char *)sys_siglist[sig];
+
+#ifdef SIGRTMIN
+ if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
+ snprintf(buf, sizeof buf, "Real-time signal %d",
+ sig - SIGRTMIN);
+ return buf;
+ }
+#endif
+
+ snprintf(buf, sizeof buf, "Signal %d", sig);
+ return buf;
+}
diff --git a/usr/klibc/strspn.c b/usr/klibc/strspn.c
new file mode 100644
index 0000000..828fa2b
--- /dev/null
+++ b/usr/klibc/strspn.c
@@ -0,0 +1,12 @@
+/*
+ * strspn
+ */
+
+#include <string.h>
+
+#include "strxspn.h"
+
+size_t strspn(const char *s, const char *accept)
+{
+ return __strxspn(s, accept, 0);
+}
diff --git a/usr/klibc/strstr.c b/usr/klibc/strstr.c
new file mode 100644
index 0000000..8850858
--- /dev/null
+++ b/usr/klibc/strstr.c
@@ -0,0 +1,11 @@
+/*
+ * strstr.c
+ */
+
+#include <string.h>
+
+char *strstr(const char *haystack, const char *needle)
+{
+ return (char *)memmem(haystack, strlen(haystack), needle,
+ strlen(needle));
+}
diff --git a/usr/klibc/strtoimax.c b/usr/klibc/strtoimax.c
new file mode 100644
index 0000000..0cdd088
--- /dev/null
+++ b/usr/klibc/strtoimax.c
@@ -0,0 +1,3 @@
+#define TYPE intmax_t
+#define NAME strtoimax
+#include "strtox.c"
diff --git a/usr/klibc/strtok.c b/usr/klibc/strtok.c
new file mode 100644
index 0000000..6b169a1
--- /dev/null
+++ b/usr/klibc/strtok.c
@@ -0,0 +1,12 @@
+/*
+ * strtok.c
+ */
+
+#include <string.h>
+
+char *strtok(char *s, const char *delim)
+{
+ static char *holder;
+
+ return strtok_r(s, delim, &holder);
+}
diff --git a/usr/klibc/strtok_r.c b/usr/klibc/strtok_r.c
new file mode 100644
index 0000000..695d516
--- /dev/null
+++ b/usr/klibc/strtok_r.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *strtok_r(char *s, const char *delim, char **holder)
+{
+ if (s)
+ *holder = s;
+
+ do {
+ s = strsep(holder, delim);
+ } while (s && !*s);
+
+ return s;
+}
diff --git a/usr/klibc/strtol.c b/usr/klibc/strtol.c
new file mode 100644
index 0000000..9efc8b9
--- /dev/null
+++ b/usr/klibc/strtol.c
@@ -0,0 +1,3 @@
+#define TYPE signed long
+#define NAME strtol
+#include "strtox.c"
diff --git a/usr/klibc/strtoll.c b/usr/klibc/strtoll.c
new file mode 100644
index 0000000..a9428c7
--- /dev/null
+++ b/usr/klibc/strtoll.c
@@ -0,0 +1,3 @@
+#define TYPE signed long long
+#define NAME strtoll
+#include "strtox.c"
diff --git a/usr/klibc/strtotimespec.c b/usr/klibc/strtotimespec.c
new file mode 100644
index 0000000..b426bf8
--- /dev/null
+++ b/usr/klibc/strtotimespec.c
@@ -0,0 +1,5 @@
+#define NAME strtotimespec
+#define TIMEX struct timespec
+#define FSEC tv_nsec
+#define DECIMALS 9
+#include "strtotimex.c"
diff --git a/usr/klibc/strtotimeval.c b/usr/klibc/strtotimeval.c
new file mode 100644
index 0000000..280d4bc
--- /dev/null
+++ b/usr/klibc/strtotimeval.c
@@ -0,0 +1,5 @@
+#define NAME strtotimeval
+#define TIMEX struct timeval
+#define FSEC tv_usec
+#define DECIMALS 6
+#include "strtotimex.c"
diff --git a/usr/klibc/strtotimex.c b/usr/klibc/strtotimex.c
new file mode 100644
index 0000000..0624082
--- /dev/null
+++ b/usr/klibc/strtotimex.c
@@ -0,0 +1,40 @@
+/*
+ * strtotimex.c
+ *
+ * Nonstandard function which takes a string and converts it to a
+ * struct timespec/timeval. Returns a pointer to the first non-numeric
+ * character in the string.
+ *
+ */
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+char *NAME(const char *str, TIMEX * ts)
+{
+ int n;
+ char *s, *s0;
+ __typeof__(ts->FSEC) fs; /* Fractional seconds */
+
+ ts->tv_sec = strntoumax(str, &s, 10, ~(size_t) 0);
+ fs = 0;
+
+ if (*s == '.') {
+ s0 = s + 1;
+
+ fs = strntoumax(s0, &s, 10, DECIMALS);
+ n = s - s0;
+
+ while (isdigit(*s))
+ s++;
+
+ for (; n < DECIMALS; n++)
+ fs *= 10;
+ }
+
+ ts->FSEC = fs;
+ return s;
+}
diff --git a/usr/klibc/strtoul.c b/usr/klibc/strtoul.c
new file mode 100644
index 0000000..3189aaa
--- /dev/null
+++ b/usr/klibc/strtoul.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long
+#define NAME strtoul
+#include "strtox.c"
diff --git a/usr/klibc/strtoull.c b/usr/klibc/strtoull.c
new file mode 100644
index 0000000..83c14e9
--- /dev/null
+++ b/usr/klibc/strtoull.c
@@ -0,0 +1,3 @@
+#define TYPE unsigned long long
+#define NAME strtoull
+#include "strtox.c"
diff --git a/usr/klibc/strtoumax.c b/usr/klibc/strtoumax.c
new file mode 100644
index 0000000..a379710
--- /dev/null
+++ b/usr/klibc/strtoumax.c
@@ -0,0 +1,3 @@
+#define TYPE uintmax_t
+#define NAME strtoumax
+#include "strtox.c"
diff --git a/usr/klibc/strtox.c b/usr/klibc/strtox.c
new file mode 100644
index 0000000..c22e7c7
--- /dev/null
+++ b/usr/klibc/strtox.c
@@ -0,0 +1,14 @@
+/*
+ * strtox.c
+ *
+ * strto...() functions, by macro definition
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+TYPE NAME(const char *nptr, char **endptr, int base)
+{
+ return (TYPE) strntoumax(nptr, endptr, base, ~(size_t) 0);
+}
diff --git a/usr/klibc/strxspn.c b/usr/klibc/strxspn.c
new file mode 100644
index 0000000..99bdbff
--- /dev/null
+++ b/usr/klibc/strxspn.c
@@ -0,0 +1,29 @@
+/*
+ * strpbrk
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <limits.h>
+#include "strxspn.h"
+
+size_t __strxspn(const char *s, const char *map, int parity)
+{
+ char matchmap[UCHAR_MAX + 1];
+ size_t n = 0;
+
+ /* Create bitmap */
+ memset(matchmap, 0, sizeof matchmap);
+ while (*map)
+ matchmap[(unsigned char)*map++] = 1;
+
+ /* Make sure the null character never matches */
+ matchmap[0] = parity;
+
+ /* Calculate span length */
+ while (matchmap[(unsigned char)*s++] ^ parity)
+ n++;
+
+ return n;
+}
diff --git a/usr/klibc/strxspn.h b/usr/klibc/strxspn.h
new file mode 100644
index 0000000..ce56ff2
--- /dev/null
+++ b/usr/klibc/strxspn.h
@@ -0,0 +1,12 @@
+/*
+ * strxspn.h
+ */
+
+#ifndef STRXSPN_H
+#define STRXSPN_H
+
+#include <stddef.h>
+
+extern size_t __strxspn(const char *s, const char *map, int parity);
+
+#endif
diff --git a/usr/klibc/symlink.c b/usr/klibc/symlink.c
new file mode 100644
index 0000000..080394f
--- /dev/null
+++ b/usr/klibc/symlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_symlink
+
+int symlink(const char *oldpath, const char *newpath)
+{
+ return symlinkat(oldpath, AT_FDCWD, newpath);
+}
+
+#endif /* __NR_symlink */
diff --git a/usr/klibc/syscalls.pl b/usr/klibc/syscalls.pl
new file mode 100644
index 0000000..3ff0222
--- /dev/null
+++ b/usr/klibc/syscalls.pl
@@ -0,0 +1,286 @@
+#!/usr/bin/perl
+#
+# Script to parse the SYSCALLS file and generate appropriate
+# stubs.
+#
+# Pass 1: generate the C array of sizes
+# Pass 2: generate the syscall stubs and other output
+#
+
+#
+# Convert a string to a C array of characters,
+# e.g. foo -> 'f','o','o','\0',
+#
+sub chararray($) {
+ use bytes;
+
+ my($s) = @_;
+ my($i, $c);
+ my($a) = '';
+
+ for ($i = 0; $i < length($s); $i++) {
+ $c = substr($s, $i, 1);
+ if (ord($c) < 32 || ord($c) > 126) {
+ $a .= sprintf("0x%02x,", ord($c));
+ } elsif ($c eq "\\" || $c eq "\'") {
+ $a .= "\'\\$c\',";
+ } else {
+ $a .= "\'$c\',";
+ }
+ }
+
+ return $a;
+}
+
+#
+# This extracts an ASCIIZ string for the type and the additional
+# information. This is open-coded, because unpack("Z*") apparently
+# is broken in Perl 5.6.1.
+#
+sub get_one_type($) {
+ use bytes;
+
+ my($typestr) = @_;
+ my $i, $c;
+ my $l = length($typestr);
+
+ for ($i = 0; $i < $l-3; $i++) {
+ $c = substr($typestr, $i, 1);
+ if ($c eq "\0") {
+ return (substr($typestr, 0, $i),
+ unpack("CC", substr($typestr, $i+1, 2)),
+ substr($typestr, $i+3));
+ }
+ }
+
+ return (undef, undef, undef, undef);
+}
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) && ($v == 0) ? 1 : undef;
+
+@args = ();
+undef $pass;
+for $arg ( @ARGV ) {
+ if ( $arg =~ /^-/ ) {
+ if ( $arg eq '-q' ) {
+ $quiet = 1;
+ } elsif ( $arg eq '-v' ) {
+ $quiet = 0;
+ } elsif ( $arg =~ /\-([0-9]+)$/ ) {
+ $pass = $1+0;
+ } else {
+ die "$0: Unknown option: $arg\n";
+ }
+ } else {
+ push(@args, $arg);
+ }
+}
+($file, $sysstub, $arch, $bits, $unistd, $outputdir,
+ $havesyscall, $typesize) = @args;
+
+if (!$pass) {
+ die "$0: Need to specify pass\n";
+}
+
+$quiet = ($pass != 2) unless defined($quiet);
+
+require "$sysstub";
+
+if (!open(UNISTD, "< $unistd\0")) {
+ die "$0: $unistd: $!\n";
+}
+
+while ( defined($line = <UNISTD>) ) {
+ chomp $line;
+
+ if ( $line =~ /^\#\s*define\s+__NR_([A-Za-z0-9_]+)\s+(.*\S)\s*$/ ) {
+ $syscalls{$1} = $2;
+ print STDERR "SYSCALL FOUND: $1\n" unless ( $quiet );
+ }
+}
+close(UNISTD);
+
+if ($pass == 2) {
+ use bytes;
+
+ if (!open(TYPESIZE, "< $typesize\0")) {
+ die "$0: $typesize: $!\n";
+ }
+
+ binmode TYPESIZE;
+
+ $len = -s TYPESIZE;
+ if (read(TYPESIZE, $typebin, $len) != $len) {
+ die "$0: $typesize: short read: $!\n";
+ }
+ close(TYPESIZE);
+
+ $ix = index($typebin, "\x7a\xc8\xdb\x4e\x97\xb4\x9c\x19");
+ if ($ix < 0) {
+ die "$0: $typesize: magic number not found\n";
+ }
+
+ # Remove magic number and bytes before it
+ $typebin = substr($typebin, $ix+8);
+
+ # Expand the types until a terminating null
+ %typesize = ();
+ while (1) {
+ my $n, $sz, $si;
+ ($n, $sz, $si, $typebin) = get_one_type($typebin);
+ last if (length($n) == 0);
+ $typesize{$n} = $sz;
+ $typesign{$n} = $si;
+ print STDERR "TYPE $n: size $sz, sign $si\n" unless ($quiet);
+ }
+} else {
+ # List here any types which should be sized even if they never occur
+ # in any system calls at all.
+ %type_list = ('int' => 1, 'long' => 1, 'long long' => 1,
+ 'void *' => 1,
+ 'intptr_t' => 1, 'uintptr_t' => 1,
+ 'intmax_t' => 1, 'uintmax_t' => 1);
+}
+
+if ($pass == 2) {
+ if (!open(HAVESYS, "> $havesyscall\0")) {
+ die "$0: $havesyscall: $!\n";
+ }
+
+ print HAVESYS "#ifndef _KLIBC_HAVESYSCALL_H\n";
+ print HAVESYS "#define _KLIBC_HAVESYSCALL_H 1\n\n";
+}
+
+if (!open(FILE, "< $file\0")) {
+ die "$0: $file: $!\n";
+}
+
+
+if ($pass == 2) {
+ print "syscall-objs := ";
+}
+
+
+while ( defined($line = <FILE>) ) {
+ chomp $line;
+ $line =~ s/\s*(|\#.*|\/\/.*)$//; # Strip comments and trailing blanks
+ next unless $line;
+
+ if ( $line =~ /^\s*(\<[^\>]+\>\s+|)([A-Za-z0-9_\*\s]+)\s+([A-Za-z0-9_,]+)(|\@[A-Za-z0-9_]+)(|\:\:[A-Za-z0-9_]+)\s*\(([^\:\)]*)\)\s*\;$/ ) {
+ $archs = $1;
+ $type = $2;
+ $snames = $3;
+ $stype = $4;
+ $fname = $5;
+ $argv = $6;
+
+ $doit = 1;
+ $maybe = 0;
+ if ( $archs ne '' ) {
+ die "$file:$.: Invalid architecture spec: <$archs>\n"
+ unless ( $archs =~ /^\<(|\?)(|\!)([^\>\!\?]*)\>/ );
+ $maybe = $1 ne '';
+ $not = $2 ne '';
+ $list = $3;
+
+ $doit = $not || ($list eq '');
+
+ @list = split(/,/, $list);
+ foreach $a ( @list ) {
+ if ( $a eq $arch || $a eq $bits ) {
+ $doit = !$not;
+ last;
+ }
+ }
+ }
+ next if ( ! $doit );
+
+ undef $sname;
+ foreach $sn ( split(/,/, $snames) ) {
+ if ( defined $syscalls{$sn} ) {
+ $sname = $sn;
+ last;
+ }
+ }
+ if ( !defined($sname) ) {
+ next if ( $maybe );
+ die "$file:$.: Undefined system call: $snames\n";
+ }
+
+ $type =~ s/\s*$//;
+ $stype =~ s/^\@//;
+
+ if ( $fname eq '' ) {
+ $fname = $sname;
+ } else {
+ $fname =~ s/^\:\://;
+ }
+
+ $argv =~ s/^\s+//;
+ $argv =~ s/\s+$//;
+
+ if ($argv eq 'void') {
+ @args = ();
+ } else {
+ @args = split(/\s*\,\s*/, $argv);
+ }
+
+ if ($pass == 1) {
+ # Pass 1: Add the types to the type list
+ foreach $a (@args) {
+ $type_list{$a}++;
+ }
+ } else {
+ # Pass 2: make sure all types defined, and actually generate stubs
+
+ foreach $a (@args) {
+ if (!defined($typesize{$a})) {
+ die "$0: $typesize: type name missing: $a\n";
+ }
+ }
+
+ print HAVESYS "#define _KLIBC_HAVE_SYSCALL_${fname} ${sname}\n";
+ print " \\\n\t${fname}.o";
+ make_sysstub($outputdir, $fname, $type, $sname, $stype, @args);
+ }
+ } else {
+ die "$file:$.: Could not parse input: \"$line\"\n";
+ }
+}
+
+if ($pass == 1) {
+ # Pass 1: generate typesize.c
+ if (!open(TYPESIZE, "> $typesize")) {
+ die "$0: cannot create file: $typesize: $!\n";
+ }
+
+ print TYPESIZE "#include \"syscommon.h\"\n";
+
+ # This compares -2 < 1 in the appropriate type, which is true for
+ # signed types and false for unsigned types. We use -2 and 1 since
+ # gcc complains about comparing unsigned types with zero, and might
+ # complain equally about -1 in the future.
+ #
+ # This test is valid (as in, doesn't cause the compiler to barf)
+ # for pointers as well as for integral types; if we ever add system
+ # calls which take any other kinds of types than that then this needs
+ # to be smarter.
+ print TYPESIZE "#define SIGNED(X) ((X)-2 < (X)1)\n";
+
+ print TYPESIZE "\n";
+ print TYPESIZE "const unsigned char type_sizes[] = {\n";
+ print TYPESIZE "\t0x7a,0xc8,0xdb,0x4e,0x97,0xb4,0x9c,0x19, /* magic */\n";
+ foreach $t (sort(keys(%type_list))) {
+ print TYPESIZE "\t", chararray($t), "0, sizeof($t), SIGNED($t),\n";
+ }
+ print TYPESIZE "\t0, 0,\n"; # End sentinel
+ print TYPESIZE "};\n";
+ close(TYPESIZE);
+} else {
+ # Pass 2: finalize output files
+ print "\n";
+
+ print HAVESYS "\n#endif\n";
+ close(HAVESYS);
+}
diff --git a/usr/klibc/syscalls/.gitignore b/usr/klibc/syscalls/.gitignore
new file mode 100644
index 0000000..d255e6e
--- /dev/null
+++ b/usr/klibc/syscalls/.gitignore
@@ -0,0 +1,6 @@
+*.S
+SYSCALLS.i
+syscalls.mk
+syscalls.nrs
+typesize.bin
+typesize.c
diff --git a/usr/klibc/syscalls/Kbuild b/usr/klibc/syscalls/Kbuild
new file mode 100644
index 0000000..3f56798
--- /dev/null
+++ b/usr/klibc/syscalls/Kbuild
@@ -0,0 +1,99 @@
+#
+# kbuild file for generating syscall stubs
+#
+
+# Include automatically generated Makefile fragment.
+# It contains definition of syscall-objs specifying name of all .o files
+ifeq ($(clean),)
+-include $(obj)/syscalls.mk
+endif
+
+# Listing of all .o files
+always := klib.list
+
+
+#####
+# Generate syscalls stubs
+# Based on list in SYSCALLS.def generate stubs for sys calls. Actual arch code
+# is defined in an arch specific perl file
+targets += syscalls.mk
+targets += klib.list
+targets += SYSCALLS.i syscalls.nrs
+targets += typesize.c typesize.o typesize.bin
+targets += $(syscall-objs)
+
+# Side effect of running syscalls.pl
+clean-files += $(objtree)/$(KLIBCINC)/klibc/havesyscall.h
+clean-files += $(KLIBCINC)/klibc/havesyscall.h
+# All the syscall stubs
+clean-files += *.o *.S *.c *.list *.bin
+
+EXTRA_KLIBCCFLAGS := -I$(srctree)/$(src)
+
+quiet_cmd_makelist = LIST $@
+ cmd_makelist = echo '$(filter-out FORCE,$^)' > $@
+
+# Create list of all files
+$(obj)/klib.list: $(call objectify,$(syscall-objs)) FORCE
+ $(call if_changed,makelist)
+
+# Generate assembler file (.i)
+# We pass -ansi to keep cpp from define e.g. "i386" as well as "__i386__"
+quiet_cmd_syscall.i = GEN $@
+ cmd_syscall.i = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__ \
+ -ansi -x c -E -o $@ $<
+$(obj)/SYSCALLS.i: $(KLIBCSRC)/SYSCALLS.def FORCE
+ $(call if_changed_dep,syscall.i)
+
+# Get syscalls numbers
+quiet_cmd_syscall.nrs = GEN $@
+ cmd_syscall.nrs = $(KLIBCCC) $(klibccflags) -Wp,-dM -x c -E -o $@ $<
+$(obj)/syscalls.nrs: $(KLIBCINC)/sys/syscall.h FORCE
+ $(call if_changed_dep,syscall.nrs)
+
+# Generate typesize.c
+quiet_cmd_syscalsz = GEN $@
+ cmd_syscalsz = \
+ mkdir -p $(KLIBCINC)/klibc/; \
+ $(PERL) $(srctree)/$(KLIBCSRC)/syscalls.pl \
+ -1 $(obj)/SYSCALLS.i \
+ $(srctree)/$(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+ $(KLIBCARCH) $(KLIBCBITSIZE) $(obj)/syscalls.nrs \
+ $(obj) \
+ $(KLIBCINC)/klibc/havesyscall.h \
+ $(obj)/typesize.c > $@ \
+ || ( rm -f $@ ; exit 1 )
+
+$(obj)/typesize.c: $(srctree)/$(KLIBCSRC)/syscalls.pl $(obj)/SYSCALLS.i \
+ $(srctree)/$(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+ $(src)/syscommon.h $(obj)/syscalls.nrs FORCE
+ $(call if_changed,syscalsz)
+
+# Convert typesize.o to typesize.bin
+quiet_cmd_mkbin = OBJCOPY $@
+ cmd_mkbin = $(KLIBCOBJCOPY) -O binary --only-section .rodata $< $@
+
+$(obj)/typesize.bin: $(obj)/typesize.o FORCE
+ $(call if_changed,mkbin)
+
+# Generate $(KLIBINC)/klibc/havesyscall.h + makefile fragment
+# Using sysstub.pl in arch dir generate all .S files
+quiet_cmd_syscalls = GEN $@
+ cmd_syscalls = \
+ mkdir -p $(KLIBCINC)/klibc/; \
+ $(PERL) $(srctree)/$(KLIBCSRC)/syscalls.pl -2 $(obj)/SYSCALLS.i \
+ $(srctree)/$(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+ $(KLIBCARCH) $(KLIBCBITSIZE) $(obj)/syscalls.nrs \
+ $(obj) \
+ $(KLIBCINC)/klibc/havesyscall.h \
+ $(obj)/typesize.bin > $@ \
+ || ( rm -f $@ ; exit 1 )
+
+$(obj)/syscalls.mk: $(srctree)/$(KLIBCSRC)/syscalls.pl $(obj)/SYSCALLS.i \
+ $(srctree)/$(KLIBCSRC)/arch/$(KLIBCARCHDIR)/sysstub.ph \
+ $(call objectify, $(syscall-objs:.o=.S)) \
+ $(src)/syscommon.h $(obj)/syscalls.nrs \
+ $(obj)/typesize.bin FORCE
+ $(call if_changed,syscalls)
+
+PHONY += FORCE
diff --git a/usr/klibc/syscalls/syscommon.h b/usr/klibc/syscalls/syscommon.h
new file mode 100644
index 0000000..78f8858
--- /dev/null
+++ b/usr/klibc/syscalls/syscommon.h
@@ -0,0 +1,34 @@
+/*
+ * syscommon.h
+ *
+ * Common header file for system call stubs
+ */
+
+#define __IN_SYS_COMMON
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#include <poll.h>
+#include <sched.h>
+#include <sys/capability.h>
+#include <sys/dirent.h>
+#include <sys/klog.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/uio.h>
+#include <sys/utime.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifdef __i386__
+# include <sys/vm86.h>
+#endif
diff --git a/usr/klibc/sysconf/sysconf.c b/usr/klibc/sysconf/sysconf.c
new file mode 100644
index 0000000..0e21beb
--- /dev/null
+++ b/usr/klibc/sysconf/sysconf.c
@@ -0,0 +1,8 @@
+#include <sys/sysconf.h>
+
+#undef sysconf
+
+long sysconf(int val)
+{
+ return __sysconf_inline(val);
+}
diff --git a/usr/klibc/syslog.c b/usr/klibc/syslog.c
new file mode 100644
index 0000000..4052eaa
--- /dev/null
+++ b/usr/klibc/syslog.c
@@ -0,0 +1,89 @@
+/*
+ * syslog.c
+ *
+ * Issue syslog messages via the kernel printk queue.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Maximum size for a kernel message */
+#define BUFLEN 1024
+
+/* Logging node */
+#define LOGDEV "/dev/kmsg"
+
+/* Max length of ID string */
+#define MAXID 31 /* MAXID+5 must be < BUFLEN */
+
+int __syslog_fd = -1;
+static char id[MAXID + 1];
+static int syslog_flags = 0;
+
+void openlog(const char *ident, int option, int facility)
+{
+ int fd;
+
+ (void)option;
+ (void)facility; /* Unused */
+
+ if (__syslog_fd == -1) {
+ __syslog_fd = fd = open(LOGDEV, O_WRONLY);
+ if (fd == -1)
+ return;
+ fcntl(fd, F_SETFD, (long)FD_CLOEXEC);
+ }
+
+ syslog_flags = option;
+
+ strncpy(id, ident ? ident : "", MAXID);
+}
+
+void vsyslog(int prio, const char *format, va_list ap)
+{
+ char buf[BUFLEN];
+ int len;
+ int fd;
+
+ if (__syslog_fd == -1)
+ openlog(NULL, 0, 0);
+
+ buf[0] = '<';
+ buf[1] = LOG_PRI(prio) + '0';
+ buf[2] = '>';
+ len = 3;
+
+ if (syslog_flags & LOG_PID)
+ len += sprintf(buf + 3, "%s[%u]: ", id, getpid());
+ else if (*id)
+ len += sprintf(buf + 3, "%s: ", id);
+
+ len += vsnprintf(buf + len, BUFLEN - len, format, ap);
+
+ if (len > BUFLEN - 1)
+ len = BUFLEN - 1;
+ if (buf[len - 1] != '\n')
+ buf[len++] = '\n';
+
+ fd = __syslog_fd;
+ if (fd == -1)
+ fd = 2; /* Failed to open log, write to stderr */
+
+ write(fd, buf, len);
+
+ if (syslog_flags & LOG_PERROR)
+ _fwrite(buf + 3, len - 3, stderr);
+}
+
+void syslog(int prio, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsyslog(prio, format, ap);
+ va_end(ap);
+}
diff --git a/usr/klibc/system.c b/usr/klibc/system.c
new file mode 100644
index 0000000..13e9fbe
--- /dev/null
+++ b/usr/klibc/system.c
@@ -0,0 +1,60 @@
+/*
+ * system.c
+ *
+ * The system() function. If this turns out to actually be *used*,
+ * we may want to try to detect the very simple cases (no shell magic)
+ * and handle them internally, instead of requiring that /bin/sh be
+ * present.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+int system(const char *string)
+{
+ pid_t pid;
+ struct sigaction ignore, old_int, old_quit;
+ sigset_t masked, oldmask;
+ static const char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+ int status;
+
+ /* Block SIGCHLD and ignore SIGINT and SIGQUIT */
+ /* Do this before the fork() to avoid races */
+
+ ignore.sa_handler = SIG_IGN;
+ sigemptyset(&ignore.sa_mask);
+ ignore.sa_flags = 0;
+ sigaction(SIGINT, &ignore, &old_int);
+ sigaction(SIGQUIT, &ignore, &old_quit);
+
+ sigemptyset(&masked);
+ sigaddset(&masked, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &masked, &oldmask);
+
+ pid = fork();
+
+ if (pid < 0)
+ return -1;
+ else if (pid == 0) {
+ sigaction(SIGINT, &old_int, NULL);
+ sigaction(SIGQUIT, &old_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ argv[2] = string;
+
+ execve(argv[0], (char *const *)argv, (char *const *)environ);
+ _exit(127);
+ }
+
+ /* else... */
+
+ waitpid(pid, &status, 0);
+
+ sigaction(SIGINT, &old_int, NULL);
+ sigaction(SIGQUIT, &old_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ return status;
+}
diff --git a/usr/klibc/sysv_signal.c b/usr/klibc/sysv_signal.c
new file mode 100644
index 0000000..beee7d7
--- /dev/null
+++ b/usr/klibc/sysv_signal.c
@@ -0,0 +1,11 @@
+/*
+ * sysv_signal.c
+ */
+
+#include <signal.h>
+
+__sighandler_t sysv_signal(int signum, __sighandler_t handler)
+{
+ /* Linux/SysV signal() semantics */
+ return __signal(signum, handler, SA_RESETHAND);
+}
diff --git a/usr/klibc/tests/Kbuild b/usr/klibc/tests/Kbuild
new file mode 100644
index 0000000..31f0308
--- /dev/null
+++ b/usr/klibc/tests/Kbuild
@@ -0,0 +1,69 @@
+#
+# Kbuild file for all test files
+#
+
+test-files := $(wildcard $(srctree)/$(src)/*.c)
+test-files := $(notdir $(test-files))
+
+# This particular file uses a bunch of formats gcc don't know of, in order
+# to test the full range of our vsnprintf() function. This outputs a bunch
+# of useless warnings unless we tell it not to.
+KLIBCCFLAGS_testvsnp.o := -Wno-format
+
+# This deliberately calls malloc() with unreasonably large values. We
+# can't use cc-disable-warning here as the option to *enable* this
+# warning requires a value.
+KLIBCCFLAGS_malloctest3.o := $(call cc-option,-Wno-alloc-size-larger-than)
+
+# Disable optimisation of these test cases based on compiler knowledge
+# of what the functions should do.
+KLIBCCFLAGS_strsearch.o := -fno-builtin-strchr -fno-builtin-strrchr \
+ -fno-builtin-strspn -fno-builtin-strcspn \
+ -fno-builtin-strpbrk -fno-builtin-strstr
+
+static-y := $(test-files:.c=)
+shared-y := $(addsuffix .shared, $(static-y))
+
+environ.shared-y := environ.o
+fcntl.shared-y := fcntl.o
+fnmatch.shared-y := fnmatch.o
+getopttest.shared-y := getopttest.o
+getoptlong.shared-y := getoptlong.o
+getpagesize.shared-y := getpagesize.o
+hello.shared-y := hello.o
+idtest.shared-y := idtest.o
+lseek.shared-y := lseek.o
+malloctest.shared-y := malloctest.o
+malloctest2.shared-y := malloctest2.o
+malloctest3.shared-y := malloctest3.o
+memstrtest.shared-y := memstrtest.o
+microhello.shared-y := microhello.o
+minihello.shared-y := minihello.o
+mmaptest.shared-y := mmaptest.o
+nfs_no_rpc.shared-y := nfs_no_rpc.o
+opentest.shared-y := opentest.o
+pipetest.shared-y := pipetest.o
+rtsig.shared-y := rtsig.o
+select.shared-y := select.o
+setenvtest.shared-y := setenvtest.o
+setjmptest.shared-y := setjmptest.o
+sigint.shared-y := sigint.o
+sig-nodefer.shared-y := sig-nodefer.o
+socket.shared-y := socket.o
+sscanf.shared-y := sscanf.o
+stat.shared-y := stat.o
+statfs.shared-y := statfs.o
+stdio.shared-y := stdio.o
+strlcpycat.shared-y := strlcpycat.o
+strsearch.shared-y := strsearch.o
+strtoimax.shared-y := strtoimax.o
+strtotime.shared-y := strtotime.o
+sysconf.shared-y := sysconf.o
+testrand48.shared-y := testrand48.o
+testvsnp.shared-y := testvsnp.o
+vfork.shared-y := vfork.o
+
+# Cleaning
+clean-files := $(static-y) $(shared-y) \
+ $(addsuffix .g, $(static-y) $(shared-y)) \
+ $(test-files:.c=.o)
diff --git a/usr/klibc/tests/environ.c b/usr/klibc/tests/environ.c
new file mode 100644
index 0000000..5253d51
--- /dev/null
+++ b/usr/klibc/tests/environ.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ int i;
+
+ /* Verify envp == environ */
+ printf("Verifying envp == environ... %s\n",
+ (envp == environ) ? "ok" : "ERROR");
+
+ /* Test argc/argv */
+ printf("argc = %d, argv = %p\n", argc, argv);
+ for (i = 0; i < argc; i++)
+ printf("argv[%2d] = %s\n", i, argv[i]);
+
+ /* Test environ */
+ for (i = 0; envp[i]; i++)
+ printf("%s\n", envp[i]);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/fcntl.c b/usr/klibc/tests/fcntl.c
new file mode 100644
index 0000000..30cc900
--- /dev/null
+++ b/usr/klibc/tests/fcntl.c
@@ -0,0 +1,51 @@
+/*
+ * Simple test of fcntl
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[])
+{
+ int fd = open(argv[0], O_RDONLY);
+ struct flock l;
+ long flags;
+
+ (void)argc;
+
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ /* Get the flags on this FD */
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ perror("F_GETFL");
+ exit(1);
+ }
+
+ if (flags != (O_RDONLY | O_LARGEFILE))
+ fprintf(stderr, "flags = %#lx\n", flags);
+
+ /* Set a lock on this FD */
+ memset(&l, 0, sizeof l);
+ l.l_type = F_RDLCK;
+ l.l_whence = SEEK_SET;
+ l.l_start = 123;
+ l.l_len = 456;
+
+ if (fcntl(fd, F_SETLK, &l) == -1) {
+ perror("F_SETLK");
+ exit(1);
+ }
+
+ /* Eventually, fork and try to conflict with this lock... */
+
+ close(fd);
+ return 0;
+}
diff --git a/usr/klibc/tests/fnmatch.c b/usr/klibc/tests/fnmatch.c
new file mode 100644
index 0000000..ff8d58e
--- /dev/null
+++ b/usr/klibc/tests/fnmatch.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+
+int main(int argc, char *argv[])
+{
+ int flags = atoi(argv[3]);
+ int match = fnmatch(argv[1], argv[2], flags);
+
+ printf("\"%s\" matches \"%s\": %d\n", argv[1], argv[2], match);
+
+ return match;
+}
diff --git a/usr/klibc/tests/getoptlong.c b/usr/klibc/tests/getoptlong.c
new file mode 100644
index 0000000..6c019b7
--- /dev/null
+++ b/usr/klibc/tests/getoptlong.c
@@ -0,0 +1,57 @@
+/*
+ * getoptlong.c
+ *
+ * Simple test for getopt_long, set the environment variable GETOPTTEST
+ * to give the argument string to getopt()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+
+static int foo = 0;
+
+static const struct option long_options[] = {
+ { "first", 1, NULL, 'f' },
+ { "second", 0, NULL, 's' },
+ { "third", 2, NULL, '3' },
+ { "fourth", 0, NULL, 4 },
+ { "set-foo", 0, &foo, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *const *argv)
+{
+ const char *parser;
+ const char *showchar;
+ char one_char[] = "\'?\'";
+ char num_buf[16];
+ int c;
+ int longindex;
+
+ parser = getenv("GETOPTTEST");
+ if (!parser)
+ parser = "abzf:o:";
+
+ do {
+ c = getopt_long(argc, argv, parser, long_options, &longindex);
+
+ if (c == EOF) {
+ showchar = "EOF";
+ } else if (c >= 32 && c <= 126) {
+ one_char[1] = c;
+ showchar = one_char;
+ } else {
+ snprintf(num_buf, sizeof num_buf, "%d", c);
+ showchar = num_buf;
+ }
+
+ printf("c = %s, optind = %d (\"%s\"), optarg = \"%s\", "
+ "optopt = \'%c\', foo = %d, longindex = %d\n",
+ showchar, optind, argv[optind],
+ optarg, optopt, foo, longindex);
+ } while (c != -1);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/getopttest.c b/usr/klibc/tests/getopttest.c
new file mode 100644
index 0000000..58619d1
--- /dev/null
+++ b/usr/klibc/tests/getopttest.c
@@ -0,0 +1,32 @@
+/*
+ * getopttest.c
+ *
+ * Simple test for getopt, set the environment variable GETOPTTEST
+ * to give the argument string to getopt()
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *const *argv)
+{
+ const char *parser;
+ char showchar[] = "\'?\'";
+ int c;
+
+ parser = getenv("GETOPTTEST");
+ if (!parser)
+ parser = "abzf:o:";
+
+ do {
+ c = getopt(argc, argv, parser);
+ showchar[1] = c;
+ printf
+ ("c = %s, optind = %d (%s), optarg = \"%s\", optopt = \'%c\'\n",
+ (c == EOF) ? "EOF" : showchar, optind, argv[optind],
+ optarg, optopt);
+ } while (c != -1);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/getpagesize.c b/usr/klibc/tests/getpagesize.c
new file mode 100644
index 0000000..1ae946a
--- /dev/null
+++ b/usr/klibc/tests/getpagesize.c
@@ -0,0 +1,10 @@
+#include <unistd.h>
+#include <stdio.h>
+
+int main(void)
+{
+ printf("getpagesize() = %d\n"
+ "__getpageshift() = %d\n", getpagesize(), __getpageshift());
+
+ return 0;
+}
diff --git a/usr/klibc/tests/hello.c b/usr/klibc/tests/hello.c
new file mode 100644
index 0000000..3f859bd
--- /dev/null
+++ b/usr/klibc/tests/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+ printf("Hello, World!\n");
+ return 0;
+}
diff --git a/usr/klibc/tests/idtest.c b/usr/klibc/tests/idtest.c
new file mode 100644
index 0000000..c3c4447
--- /dev/null
+++ b/usr/klibc/tests/idtest.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void)
+{
+ printf("pid = %u\n", getpid());
+ printf("ppid = %u\n", getppid());
+ printf("uid = %u\n", getuid());
+ printf("euid = %u\n", geteuid());
+ printf("gid = %u\n", getgid());
+ printf("egid = %u\n", getegid());
+ sleep(10);
+ return 0;
+}
diff --git a/usr/klibc/tests/lseek.c b/usr/klibc/tests/lseek.c
new file mode 100644
index 0000000..c4e7f54
--- /dev/null
+++ b/usr/klibc/tests/lseek.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(void)
+{
+ int fd = open("test.out", O_RDWR|O_CREAT|O_TRUNC, 0666);
+ off_t rv;
+
+ rv = lseek(fd, 123456789012ULL, SEEK_SET);
+
+ printf("seek to: %lld\n", rv);
+ return 0;
+}
diff --git a/usr/klibc/tests/malloctest.c b/usr/klibc/tests/malloctest.c
new file mode 100644
index 0000000..2ae184e
--- /dev/null
+++ b/usr/klibc/tests/malloctest.c
@@ -0,0 +1,4146 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define NCYCLES 4096
+
+int sizes[NCYCLES] = {
+ 11986,
+ 277806,
+ 2659,
+ 46,
+ 0,
+ 775553,
+ 1991,
+ 21,
+ 7638,
+ 250197,
+ 155828,
+ 5777,
+ 9,
+ 315006,
+ 900788,
+ 0,
+ 24893,
+ 119996,
+ 72299,
+ 171266,
+ 357,
+ 560,
+ 368,
+ 22952,
+ 54058,
+ 12638,
+ 39155,
+ 2738,
+ 217563,
+ 26853,
+ 47,
+ 75,
+ 1167,
+ 16917,
+ 1899,
+ 2905,
+ 9337,
+ 62243,
+ 14214,
+ 270523,
+ 4024,
+ 21,
+ 32,
+ 14892,
+ 625144,
+ 13,
+ 21700,
+ 8804,
+ 254147,
+ 0,
+ 6,
+ 836004,
+ 1718,
+ 2289,
+ 15554,
+ 412857,
+ 185097,
+ 806709,
+ 64,
+ 18602,
+ 17064,
+ 1779,
+ 78153,
+ 170600,
+ 199100,
+ 546528,
+ 0,
+ 21,
+ 20609,
+ 16514,
+ 548196,
+ 311446,
+ 53484,
+ 0,
+ 551,
+ 22225,
+ 24,
+ 153989,
+ 457309,
+ 526833,
+ 227979,
+ 757167,
+ 429560,
+ 0,
+ 835,
+ 1702,
+ 475275,
+ 798416,
+ 753,
+ 0,
+ 11126,
+ 145779,
+ 2006,
+ 0,
+ 8182,
+ 0,
+ 569432,
+ 9671,
+ 36,
+ 5523,
+ 407325,
+ 0,
+ 65,
+ 9293,
+ 0,
+ 6793,
+ 468701,
+ 73,
+ 0,
+ 186236,
+ 0,
+ 328405,
+ 125616,
+ 508013,
+ 380519,
+ 599518,
+ 83,
+ 151973,
+ 466906,
+ 9029,
+ 159725,
+ 1316,
+ 1,
+ 911532,
+ 1508,
+ 19050,
+ 972850,
+ 126,
+ 439377,
+ 29,
+ 37928,
+ 149628,
+ 54,
+ 130248,
+ 2,
+ 143,
+ 0,
+ 716873,
+ 3327,
+ 5,
+ 116131,
+ 5124,
+ 559621,
+ 2886,
+ 534,
+ 186432,
+ 441,
+ 7348,
+ 10331,
+ 1,
+ 260935,
+ 7,
+ 4370,
+ 405415,
+ 2,
+ 84518,
+ 1970,
+ 1,
+ 281910,
+ 46,
+ 274,
+ 2273,
+ 370565,
+ 4190,
+ 820641,
+ 577970,
+ 32809,
+ 974893,
+ 398067,
+ 380698,
+ 4,
+ 25978,
+ 153,
+ 882668,
+ 312365,
+ 9523,
+ 156421,
+ 0,
+ 268143,
+ 6,
+ 2,
+ 42987,
+ 212,
+ 12303,
+ 6723,
+ 1179,
+ 0,
+ 120924,
+ 3877,
+ 330421,
+ 310445,
+ 39264,
+ 8,
+ 85380,
+ 464716,
+ 0,
+ 33657,
+ 6285,
+ 0,
+ 4491,
+ 229,
+ 50,
+ 373197,
+ 6029,
+ 19,
+ 86884,
+ 243745,
+ 335656,
+ 90945,
+ 38973,
+ 572950,
+ 164129,
+ 0,
+ 3,
+ 17,
+ 13579,
+ 4448,
+ 47,
+ 3,
+ 132966,
+ 726249,
+ 498503,
+ 256,
+ 0,
+ 25841,
+ 0,
+ 7,
+ 945380,
+ 11872,
+ 69,
+ 3799,
+ 77223,
+ 1914,
+ 73,
+ 810968,
+ 10223,
+ 257918,
+ 184252,
+ 350,
+ 8101,
+ 725,
+ 9,
+ 2,
+ 2089,
+ 175,
+ 247,
+ 185964,
+ 36517,
+ 3723,
+ 313465,
+ 209,
+ 1300,
+ 128071,
+ 7425,
+ 2436,
+ 62,
+ 13753,
+ 9514,
+ 41,
+ 409141,
+ 46643,
+ 20866,
+ 15664,
+ 388548,
+ 84692,
+ 9549,
+ 610,
+ 7213,
+ 14,
+ 14930,
+ 244719,
+ 4748,
+ 41682,
+ 401098,
+ 102506,
+ 176535,
+ 0,
+ 5133,
+ 548,
+ 5234,
+ 56,
+ 11101,
+ 87638,
+ 336579,
+ 291705,
+ 640250,
+ 768165,
+ 370,
+ 2809,
+ 3,
+ 0,
+ 445122,
+ 47190,
+ 24885,
+ 143556,
+ 84,
+ 504726,
+ 610020,
+ 40355,
+ 902230,
+ 4360,
+ 1747,
+ 3496,
+ 489501,
+ 19,
+ 801601,
+ 62189,
+ 48,
+ 2645,
+ 320601,
+ 27304,
+ 17740,
+ 344,
+ 10,
+ 991,
+ 925503,
+ 0,
+ 315,
+ 251,
+ 3611,
+ 1756,
+ 683,
+ 165,
+ 380132,
+ 181101,
+ 453041,
+ 892056,
+ 67191,
+ 252592,
+ 32407,
+ 56242,
+ 8,
+ 297173,
+ 542903,
+ 830334,
+ 585236,
+ 422555,
+ 44769,
+ 0,
+ 68,
+ 4143,
+ 38754,
+ 73539,
+ 44579,
+ 94001,
+ 428537,
+ 38554,
+ 106612,
+ 0,
+ 182987,
+ 831731,
+ 3605,
+ 752851,
+ 52,
+ 72,
+ 120872,
+ 963754,
+ 31,
+ 764,
+ 240592,
+ 99101,
+ 328538,
+ 440325,
+ 12211,
+ 151282,
+ 353436,
+ 2991,
+ 40710,
+ 5212,
+ 5106,
+ 139122,
+ 148915,
+ 498505,
+ 1366,
+ 516,
+ 29190,
+ 17,
+ 224208,
+ 40,
+ 89,
+ 19190,
+ 8,
+ 25377,
+ 10029,
+ 720,
+ 97963,
+ 0,
+ 614,
+ 244567,
+ 2113,
+ 903675,
+ 8388,
+ 6,
+ 390705,
+ 325006,
+ 284272,
+ 108086,
+ 17,
+ 2628,
+ 952530,
+ 20474,
+ 898276,
+ 138661,
+ 3883,
+ 903,
+ 569993,
+ 376918,
+ 5849,
+ 103404,
+ 794499,
+ 35388,
+ 5,
+ 0,
+ 961626,
+ 27415,
+ 1927,
+ 92036,
+ 46241,
+ 35978,
+ 7426,
+ 399884,
+ 29490,
+ 252655,
+ 675971,
+ 3509,
+ 54170,
+ 170790,
+ 831341,
+ 134579,
+ 0,
+ 790422,
+ 35,
+ 930830,
+ 97394,
+ 20265,
+ 670,
+ 38497,
+ 1759,
+ 71209,
+ 93,
+ 736,
+ 11,
+ 886,
+ 1961,
+ 7,
+ 210607,
+ 62226,
+ 186736,
+ 1518,
+ 5,
+ 5,
+ 13,
+ 66989,
+ 442321,
+ 0,
+ 607939,
+ 11253,
+ 210875,
+ 495530,
+ 2,
+ 221136,
+ 377663,
+ 372,
+ 200658,
+ 18591,
+ 129783,
+ 803411,
+ 867506,
+ 757446,
+ 48836,
+ 34,
+ 200,
+ 114983,
+ 7287,
+ 22849,
+ 226669,
+ 13,
+ 0,
+ 20164,
+ 7828,
+ 39,
+ 49448,
+ 26740,
+ 185566,
+ 9927,
+ 36192,
+ 91068,
+ 338368,
+ 926,
+ 27746,
+ 534794,
+ 936132,
+ 2922,
+ 5,
+ 183162,
+ 256846,
+ 242551,
+ 134318,
+ 212959,
+ 167162,
+ 470,
+ 477045,
+ 532116,
+ 483794,
+ 733,
+ 5335,
+ 83074,
+ 4686,
+ 9567,
+ 1,
+ 195100,
+ 40354,
+ 87338,
+ 369,
+ 800,
+ 0,
+ 194504,
+ 469051,
+ 363532,
+ 850574,
+ 5085,
+ 167027,
+ 794511,
+ 124320,
+ 303231,
+ 132195,
+ 13225,
+ 46333,
+ 4313,
+ 89,
+ 799,
+ 51482,
+ 0,
+ 26,
+ 12659,
+ 1045,
+ 23621,
+ 0,
+ 74926,
+ 490979,
+ 6,
+ 3188,
+ 9448,
+ 174730,
+ 38982,
+ 102317,
+ 189621,
+ 853,
+ 29227,
+ 43374,
+ 423,
+ 420951,
+ 686,
+ 128,
+ 31291,
+ 0,
+ 402819,
+ 663143,
+ 55903,
+ 142,
+ 2,
+ 331584,
+ 197164,
+ 7,
+ 671983,
+ 53,
+ 5020,
+ 9782,
+ 123,
+ 743407,
+ 1276,
+ 1115,
+ 1169,
+ 122752,
+ 824690,
+ 292030,
+ 2094,
+ 144626,
+ 0,
+ 297278,
+ 440,
+ 742,
+ 95879,
+ 17682,
+ 10654,
+ 31,
+ 22183,
+ 746,
+ 0,
+ 0,
+ 11185,
+ 28,
+ 394987,
+ 36,
+ 474,
+ 243749,
+ 1431,
+ 56702,
+ 76,
+ 15619,
+ 33071,
+ 12181,
+ 158647,
+ 261786,
+ 1,
+ 119783,
+ 48816,
+ 6278,
+ 4121,
+ 61122,
+ 69,
+ 48790,
+ 345335,
+ 275917,
+ 964393,
+ 424,
+ 586433,
+ 20519,
+ 18156,
+ 756400,
+ 27736,
+ 458706,
+ 1,
+ 3286,
+ 929624,
+ 1883,
+ 2,
+ 1086,
+ 439501,
+ 552,
+ 157132,
+ 5565,
+ 105061,
+ 8199,
+ 23,
+ 178797,
+ 0,
+ 130644,
+ 1,
+ 6952,
+ 754,
+ 500,
+ 647683,
+ 0,
+ 959079,
+ 622561,
+ 1131,
+ 559783,
+ 6862,
+ 175420,
+ 408671,
+ 463461,
+ 55908,
+ 606496,
+ 169,
+ 49060,
+ 247,
+ 953,
+ 333030,
+ 0,
+ 23399,
+ 29193,
+ 9303,
+ 15,
+ 515402,
+ 34961,
+ 365856,
+ 633043,
+ 173,
+ 556089,
+ 1809,
+ 12215,
+ 14,
+ 316,
+ 20642,
+ 9,
+ 15,
+ 190391,
+ 951463,
+ 25059,
+ 13654,
+ 385040,
+ 4272,
+ 929033,
+ 208813,
+ 35166,
+ 42849,
+ 662648,
+ 254811,
+ 4230,
+ 812459,
+ 681,
+ 390168,
+ 5381,
+ 4662,
+ 173257,
+ 478863,
+ 103,
+ 89332,
+ 0,
+ 0,
+ 589484,
+ 19369,
+ 94,
+ 9,
+ 639917,
+ 1110,
+ 393,
+ 101040,
+ 911,
+ 152899,
+ 0,
+ 2,
+ 0,
+ 0,
+ 335691,
+ 43694,
+ 62273,
+ 200121,
+ 2250,
+ 621004,
+ 149918,
+ 41063,
+ 218229,
+ 0,
+ 497924,
+ 16832,
+ 587071,
+ 0,
+ 0,
+ 729918,
+ 2,
+ 808513,
+ 9417,
+ 718,
+ 0,
+ 2769,
+ 28704,
+ 1335,
+ 734726,
+ 219157,
+ 786230,
+ 981004,
+ 350788,
+ 884529,
+ 0,
+ 87872,
+ 34647,
+ 85469,
+ 4524,
+ 339838,
+ 38228,
+ 0,
+ 4151,
+ 1145,
+ 0,
+ 351,
+ 167956,
+ 810075,
+ 689,
+ 251212,
+ 583068,
+ 2929,
+ 189456,
+ 2089,
+ 48749,
+ 278952,
+ 77134,
+ 0,
+ 0,
+ 45595,
+ 281829,
+ 969602,
+ 43999,
+ 69824,
+ 856982,
+ 61732,
+ 336,
+ 25488,
+ 213,
+ 46683,
+ 1909,
+ 174097,
+ 57930,
+ 91466,
+ 828418,
+ 95740,
+ 378828,
+ 128065,
+ 68068,
+ 0,
+ 13312,
+ 26006,
+ 6760,
+ 51,
+ 276081,
+ 640068,
+ 634985,
+ 7131,
+ 784882,
+ 790126,
+ 628585,
+ 205824,
+ 764965,
+ 17793,
+ 3159,
+ 649924,
+ 0,
+ 37383,
+ 9919,
+ 353,
+ 0,
+ 149003,
+ 620629,
+ 95928,
+ 2560,
+ 504343,
+ 1000,
+ 32,
+ 43836,
+ 407031,
+ 207,
+ 800894,
+ 3222,
+ 51028,
+ 7,
+ 6,
+ 22010,
+ 0,
+ 21174,
+ 12893,
+ 824932,
+ 7305,
+ 70,
+ 624258,
+ 372139,
+ 21504,
+ 387996,
+ 418931,
+ 914268,
+ 576,
+ 0,
+ 0,
+ 618224,
+ 787516,
+ 133014,
+ 422,
+ 383124,
+ 656318,
+ 4420,
+ 6082,
+ 244813,
+ 38585,
+ 3200,
+ 1,
+ 2,
+ 11882,
+ 113,
+ 45581,
+ 13121,
+ 95475,
+ 807219,
+ 8195,
+ 995116,
+ 13,
+ 2146,
+ 369925,
+ 60103,
+ 25,
+ 125165,
+ 51300,
+ 4894,
+ 173261,
+ 74186,
+ 1044,
+ 122992,
+ 1243,
+ 21703,
+ 26294,
+ 197,
+ 333825,
+ 426872,
+ 719580,
+ 3598,
+ 106,
+ 0,
+ 9932,
+ 61509,
+ 146,
+ 721428,
+ 964781,
+ 319850,
+ 573802,
+ 7458,
+ 317889,
+ 0,
+ 133086,
+ 87836,
+ 60496,
+ 304249,
+ 1565,
+ 27,
+ 42,
+ 899324,
+ 189637,
+ 8648,
+ 104570,
+ 901598,
+ 447765,
+ 24,
+ 108,
+ 120127,
+ 828626,
+ 8,
+ 899514,
+ 28,
+ 13,
+ 7576,
+ 163390,
+ 1625,
+ 3023,
+ 155175,
+ 2,
+ 391,
+ 1,
+ 493073,
+ 398,
+ 210771,
+ 26266,
+ 287999,
+ 38255,
+ 249666,
+ 598202,
+ 119601,
+ 216933,
+ 91205,
+ 0,
+ 7247,
+ 77077,
+ 565383,
+ 29102,
+ 253641,
+ 48855,
+ 19722,
+ 463536,
+ 40182,
+ 65393,
+ 829444,
+ 598402,
+ 1590,
+ 798,
+ 467,
+ 834847,
+ 3007,
+ 13711,
+ 0,
+ 195,
+ 101662,
+ 255749,
+ 129201,
+ 11965,
+ 1781,
+ 13349,
+ 3100,
+ 718066,
+ 99,
+ 712450,
+ 888215,
+ 42503,
+ 43171,
+ 494946,
+ 0,
+ 2175,
+ 12387,
+ 25662,
+ 78,
+ 739030,
+ 0,
+ 19,
+ 427526,
+ 4275,
+ 5583,
+ 0,
+ 2447,
+ 132398,
+ 26437,
+ 3873,
+ 440035,
+ 21,
+ 6,
+ 35432,
+ 41523,
+ 7179,
+ 712703,
+ 428868,
+ 2793,
+ 6,
+ 286277,
+ 1882,
+ 95116,
+ 2959,
+ 86,
+ 115425,
+ 81386,
+ 59836,
+ 37,
+ 247598,
+ 34732,
+ 249,
+ 500110,
+ 5589,
+ 40319,
+ 575,
+ 12145,
+ 385829,
+ 565600,
+ 582150,
+ 92,
+ 223209,
+ 0,
+ 910,
+ 1048,
+ 47329,
+ 90944,
+ 235,
+ 8739,
+ 686685,
+ 1753,
+ 126,
+ 434,
+ 609477,
+ 25021,
+ 6610,
+ 52675,
+ 4,
+ 717846,
+ 150864,
+ 418583,
+ 17751,
+ 513794,
+ 181362,
+ 329556,
+ 10426,
+ 717019,
+ 457,
+ 616,
+ 388984,
+ 17,
+ 8338,
+ 59531,
+ 32,
+ 99565,
+ 376146,
+ 134578,
+ 966,
+ 0,
+ 0,
+ 174,
+ 2105,
+ 555,
+ 8990,
+ 298,
+ 169932,
+ 247281,
+ 240918,
+ 298655,
+ 158743,
+ 15994,
+ 95708,
+ 51,
+ 2985,
+ 4294,
+ 731934,
+ 185640,
+ 1483,
+ 87,
+ 742033,
+ 9,
+ 1345,
+ 3680,
+ 133530,
+ 9355,
+ 800111,
+ 28508,
+ 0,
+ 369,
+ 31681,
+ 24,
+ 8237,
+ 313380,
+ 4732,
+ 275423,
+ 951592,
+ 0,
+ 41381,
+ 225515,
+ 393004,
+ 526,
+ 187,
+ 19515,
+ 6006,
+ 28923,
+ 310151,
+ 2390,
+ 374,
+ 0,
+ 19142,
+ 72,
+ 114,
+ 193305,
+ 24035,
+ 397067,
+ 18,
+ 14839,
+ 3473,
+ 164,
+ 104622,
+ 378958,
+ 2218,
+ 0,
+ 89053,
+ 105183,
+ 312265,
+ 82146,
+ 147210,
+ 3419,
+ 5178,
+ 34948,
+ 46836,
+ 41319,
+ 842825,
+ 595972,
+ 0,
+ 249625,
+ 325,
+ 608,
+ 372328,
+ 119634,
+ 7504,
+ 920214,
+ 7302,
+ 444532,
+ 359213,
+ 27265,
+ 1755,
+ 48,
+ 126799,
+ 651270,
+ 818220,
+ 799493,
+ 724024,
+ 64047,
+ 73699,
+ 206999,
+ 209,
+ 1581,
+ 0,
+ 42937,
+ 301144,
+ 73416,
+ 0,
+ 242058,
+ 29660,
+ 3,
+ 34709,
+ 162719,
+ 2863,
+ 3992,
+ 5212,
+ 151814,
+ 3092,
+ 198001,
+ 44331,
+ 36,
+ 407,
+ 364771,
+ 1349,
+ 502772,
+ 214726,
+ 607,
+ 388583,
+ 137660,
+ 337124,
+ 13279,
+ 10549,
+ 943075,
+ 164068,
+ 19157,
+ 38443,
+ 26351,
+ 0,
+ 67167,
+ 735,
+ 46486,
+ 130305,
+ 232330,
+ 744,
+ 882337,
+ 2,
+ 69275,
+ 126354,
+ 9370,
+ 2845,
+ 299,
+ 38988,
+ 37834,
+ 0,
+ 306433,
+ 9139,
+ 237132,
+ 0,
+ 500,
+ 13462,
+ 373684,
+ 107453,
+ 381924,
+ 347915,
+ 4329,
+ 1668,
+ 3960,
+ 370661,
+ 3614,
+ 636048,
+ 0,
+ 487449,
+ 64925,
+ 333894,
+ 11,
+ 52192,
+ 531200,
+ 155554,
+ 461,
+ 1547,
+ 994361,
+ 11955,
+ 321056,
+ 37425,
+ 14249,
+ 69151,
+ 621862,
+ 174,
+ 79607,
+ 34,
+ 77577,
+ 13723,
+ 267550,
+ 13801,
+ 698,
+ 12,
+ 171556,
+ 57354,
+ 676845,
+ 0,
+ 24965,
+ 908955,
+ 570483,
+ 0,
+ 296387,
+ 983966,
+ 85012,
+ 130298,
+ 151946,
+ 384474,
+ 731455,
+ 150699,
+ 772,
+ 216131,
+ 346,
+ 130935,
+ 3472,
+ 18,
+ 426045,
+ 677262,
+ 808,
+ 17030,
+ 5188,
+ 0,
+ 491153,
+ 67299,
+ 19,
+ 60342,
+ 69,
+ 0,
+ 76478,
+ 95763,
+ 0,
+ 28778,
+ 147869,
+ 335927,
+ 27846,
+ 2163,
+ 22750,
+ 162,
+ 23,
+ 11391,
+ 469099,
+ 5852,
+ 63,
+ 0,
+ 0,
+ 22193,
+ 165,
+ 489007,
+ 9249,
+ 12477,
+ 2841,
+ 223532,
+ 13877,
+ 173,
+ 3570,
+ 45477,
+ 233073,
+ 23296,
+ 64377,
+ 4910,
+ 8,
+ 76246,
+ 411147,
+ 287411,
+ 10450,
+ 3667,
+ 1,
+ 500933,
+ 31363,
+ 257,
+ 1705,
+ 6036,
+ 49934,
+ 13738,
+ 13485,
+ 61608,
+ 561978,
+ 76493,
+ 16377,
+ 1817,
+ 0,
+ 235600,
+ 0,
+ 16347,
+ 680478,
+ 5115,
+ 895607,
+ 138270,
+ 369912,
+ 53110,
+ 0,
+ 647083,
+ 85,
+ 458681,
+ 163227,
+ 52767,
+ 196,
+ 267719,
+ 14047,
+ 147293,
+ 814457,
+ 174896,
+ 0,
+ 34138,
+ 36,
+ 21575,
+ 3,
+ 0,
+ 0,
+ 38391,
+ 2597,
+ 2,
+ 1433,
+ 3807,
+ 36476,
+ 287,
+ 141530,
+ 29389,
+ 495655,
+ 30014,
+ 0,
+ 550766,
+ 11958,
+ 348,
+ 226760,
+ 15,
+ 251353,
+ 675788,
+ 518308,
+ 215,
+ 81987,
+ 409862,
+ 559596,
+ 114283,
+ 4925,
+ 0,
+ 17,
+ 14221,
+ 0,
+ 162,
+ 766370,
+ 4898,
+ 998,
+ 493,
+ 138418,
+ 265159,
+ 12152,
+ 5229,
+ 1204,
+ 1814,
+ 432530,
+ 2889,
+ 144,
+ 1149,
+ 35886,
+ 636931,
+ 6640,
+ 1508,
+ 414118,
+ 858,
+ 20039,
+ 17398,
+ 3,
+ 5094,
+ 6,
+ 13996,
+ 6754,
+ 362,
+ 451487,
+ 11471,
+ 7896,
+ 330009,
+ 244269,
+ 99928,
+ 0,
+ 14311,
+ 9949,
+ 15251,
+ 283923,
+ 123754,
+ 188360,
+ 93902,
+ 854384,
+ 548001,
+ 531788,
+ 26298,
+ 328479,
+ 941,
+ 246535,
+ 106320,
+ 28769,
+ 440,
+ 4,
+ 61262,
+ 55615,
+ 170,
+ 989327,
+ 692534,
+ 8063,
+ 445842,
+ 4434,
+ 255349,
+ 117781,
+ 6,
+ 9249,
+ 136216,
+ 38165,
+ 307012,
+ 12,
+ 2341,
+ 18062,
+ 371882,
+ 662154,
+ 12623,
+ 176847,
+ 332220,
+ 590935,
+ 33682,
+ 0,
+ 121374,
+ 67,
+ 46841,
+ 495890,
+ 640,
+ 19,
+ 14737,
+ 11032,
+ 17,
+ 5993,
+ 302562,
+ 827710,
+ 165346,
+ 49607,
+ 87863,
+ 308513,
+ 735300,
+ 1914,
+ 2900,
+ 207308,
+ 9068,
+ 83494,
+ 179,
+ 417,
+ 41605,
+ 74681,
+ 652171,
+ 4013,
+ 29811,
+ 13966,
+ 8136,
+ 78,
+ 61182,
+ 674187,
+ 0,
+ 331121,
+ 0,
+ 18559,
+ 386,
+ 77,
+ 348439,
+ 975358,
+ 18,
+ 33700,
+ 47396,
+ 204751,
+ 2350,
+ 26503,
+ 0,
+ 83653,
+ 446,
+ 10844,
+ 485,
+ 9241,
+ 88347,
+ 232419,
+ 936900,
+ 43250,
+ 2,
+ 26112,
+ 811955,
+ 20723,
+ 102069,
+ 42255,
+ 8431,
+ 119508,
+ 4080,
+ 13565,
+ 12,
+ 46110,
+ 62096,
+ 638777,
+ 44025,
+ 152985,
+ 13362,
+ 3,
+ 12331,
+ 193337,
+ 56419,
+ 14593,
+ 3837,
+ 282314,
+ 403454,
+ 48589,
+ 135,
+ 18350,
+ 2160,
+ 90,
+ 918216,
+ 7083,
+ 105534,
+ 742826,
+ 399028,
+ 1470,
+ 23770,
+ 480,
+ 677884,
+ 340472,
+ 107406,
+ 0,
+ 5002,
+ 445,
+ 748948,
+ 534012,
+ 592464,
+ 6539,
+ 819632,
+ 3138,
+ 4,
+ 39397,
+ 229683,
+ 12204,
+ 2439,
+ 65131,
+ 817226,
+ 22596,
+ 0,
+ 1046,
+ 94638,
+ 0,
+ 95403,
+ 1230,
+ 790056,
+ 19976,
+ 43085,
+ 14251,
+ 139187,
+ 20232,
+ 693,
+ 3058,
+ 27654,
+ 65690,
+ 40948,
+ 15001,
+ 21089,
+ 14425,
+ 322459,
+ 13571,
+ 228154,
+ 536814,
+ 761221,
+ 28030,
+ 2322,
+ 921,
+ 1,
+ 1137,
+ 187815,
+ 8,
+ 34911,
+ 4527,
+ 15,
+ 46,
+ 78801,
+ 0,
+ 73605,
+ 44,
+ 28233,
+ 1370,
+ 73409,
+ 198159,
+ 66586,
+ 3,
+ 2576,
+ 15,
+ 35460,
+ 263237,
+ 44997,
+ 2873,
+ 240,
+ 1781,
+ 269,
+ 46,
+ 272778,
+ 28404,
+ 8232,
+ 417073,
+ 234591,
+ 9,
+ 720349,
+ 1176,
+ 16195,
+ 0,
+ 9705,
+ 0,
+ 14,
+ 947048,
+ 163,
+ 76288,
+ 1115,
+ 267020,
+ 3416,
+ 414217,
+ 441004,
+ 95131,
+ 765002,
+ 6196,
+ 9069,
+ 27017,
+ 137039,
+ 65247,
+ 266489,
+ 484945,
+ 187008,
+ 45405,
+ 5700,
+ 9,
+ 7751,
+ 12,
+ 294,
+ 3093,
+ 6350,
+ 103303,
+ 6045,
+ 252345,
+ 140207,
+ 22390,
+ 234867,
+ 443326,
+ 1,
+ 0,
+ 89972,
+ 8637,
+ 427150,
+ 22146,
+ 0,
+ 310432,
+ 390333,
+ 10461,
+ 1632,
+ 31403,
+ 908653,
+ 0,
+ 6543,
+ 163479,
+ 67608,
+ 195543,
+ 315889,
+ 822964,
+ 383536,
+ 954954,
+ 1619,
+ 241,
+ 96053,
+ 104556,
+ 767302,
+ 2469,
+ 12,
+ 164330,
+ 78,
+ 141,
+ 170519,
+ 268214,
+ 53338,
+ 48342,
+ 721,
+ 58980,
+ 4345,
+ 1,
+ 856265,
+ 87289,
+ 57219,
+ 775679,
+ 123992,
+ 695804,
+ 113025,
+ 832,
+ 117420,
+ 16634,
+ 352,
+ 24729,
+ 14973,
+ 25622,
+ 131290,
+ 0,
+ 22,
+ 87740,
+ 5917,
+ 533,
+ 2934,
+ 34261,
+ 9174,
+ 0,
+ 1656,
+ 764587,
+ 54652,
+ 35597,
+ 36389,
+ 577889,
+ 63957,
+ 26808,
+ 34556,
+ 56,
+ 15641,
+ 137,
+ 1,
+ 3,
+ 11724,
+ 197397,
+ 39027,
+ 87902,
+ 320,
+ 791479,
+ 7,
+ 487864,
+ 0,
+ 433,
+ 25733,
+ 6956,
+ 15407,
+ 312557,
+ 526302,
+ 383019,
+ 340215,
+ 96,
+ 276158,
+ 6493,
+ 135613,
+ 2000,
+ 1218,
+ 930,
+ 276808,
+ 273249,
+ 8896,
+ 397,
+ 735095,
+ 20648,
+ 2079,
+ 5349,
+ 205,
+ 356313,
+ 841954,
+ 8255,
+ 266874,
+ 0,
+ 965,
+ 287993,
+ 1549,
+ 207833,
+ 75,
+ 178180,
+ 39072,
+ 0,
+ 43254,
+ 3847,
+ 227,
+ 2712,
+ 161043,
+ 463264,
+ 74720,
+ 795789,
+ 12,
+ 6812,
+ 202804,
+ 29379,
+ 64241,
+ 132121,
+ 790622,
+ 493588,
+ 0,
+ 48,
+ 147352,
+ 925197,
+ 38149,
+ 18380,
+ 0,
+ 270280,
+ 633,
+ 3373,
+ 31294,
+ 7830,
+ 0,
+ 0,
+ 11371,
+ 56143,
+ 5393,
+ 74724,
+ 495109,
+ 0,
+ 18993,
+ 21524,
+ 0,
+ 53889,
+ 400509,
+ 204563,
+ 0,
+ 11625,
+ 9635,
+ 0,
+ 1678,
+ 12096,
+ 59,
+ 817112,
+ 10002,
+ 128209,
+ 11593,
+ 17313,
+ 15200,
+ 106796,
+ 261401,
+ 707077,
+ 0,
+ 314030,
+ 798591,
+ 14175,
+ 5668,
+ 2766,
+ 0,
+ 566,
+ 5543,
+ 24112,
+ 154482,
+ 5642,
+ 0,
+ 38410,
+ 3,
+ 4,
+ 700724,
+ 25024,
+ 5,
+ 407,
+ 564150,
+ 672,
+ 143,
+ 2049,
+ 574708,
+ 65858,
+ 213412,
+ 3797,
+ 511,
+ 30907,
+ 1212,
+ 765,
+ 2127,
+ 481,
+ 130048,
+ 113816,
+ 39861,
+ 153169,
+ 503378,
+ 523944,
+ 111,
+ 55083,
+ 698,
+ 275,
+ 3,
+ 3195,
+ 1657,
+ 0,
+ 317881,
+ 6672,
+ 543,
+ 153011,
+ 77240,
+ 9338,
+ 889850,
+ 29518,
+ 872485,
+ 181927,
+ 376086,
+ 266,
+ 409,
+ 4,
+ 14856,
+ 31943,
+ 2448,
+ 8,
+ 75,
+ 383097,
+ 294366,
+ 0,
+ 173084,
+ 753160,
+ 66457,
+ 725783,
+ 51,
+ 127651,
+ 1073,
+ 12598,
+ 140080,
+ 0,
+ 296375,
+ 581720,
+ 217346,
+ 8272,
+ 2051,
+ 185390,
+ 520645,
+ 1260,
+ 13873,
+ 168040,
+ 19690,
+ 103347,
+ 295011,
+ 548404,
+ 48,
+ 4,
+ 916417,
+ 1948,
+ 621365,
+ 263245,
+ 2792,
+ 86803,
+ 181193,
+ 558081,
+ 50907,
+ 442770,
+ 51448,
+ 340276,
+ 1346,
+ 607,
+ 459627,
+ 0,
+ 30,
+ 73298,
+ 15389,
+ 12264,
+ 2719,
+ 2936,
+ 143043,
+ 209970,
+ 0,
+ 42,
+ 6657,
+ 317419,
+ 0,
+ 32622,
+ 524000,
+ 0,
+ 310331,
+ 303778,
+ 268710,
+ 9,
+ 10410,
+ 25343,
+ 949506,
+ 784353,
+ 3861,
+ 46823,
+ 251292,
+ 75008,
+ 269798,
+ 87731,
+ 112813,
+ 571679,
+ 385,
+ 3,
+ 2811,
+ 36025,
+ 9243,
+ 935128,
+ 906,
+ 10688,
+ 25,
+ 86757,
+ 307,
+ 55,
+ 22,
+ 2,
+ 61,
+ 620426,
+ 484530,
+ 633806,
+ 0,
+ 1342,
+ 9293,
+ 992181,
+ 503,
+ 195433,
+ 46150,
+ 893091,
+ 3207,
+ 2865,
+ 72894,
+ 830299,
+ 355,
+ 327479,
+ 0,
+ 35573,
+ 3068,
+ 15699,
+ 31187,
+ 55378,
+ 416067,
+ 91721,
+ 159,
+ 0,
+ 255139,
+ 2104,
+ 19,
+ 606757,
+ 323,
+ 902659,
+ 365655,
+ 400,
+ 903,
+ 408,
+ 385,
+ 21774,
+ 701290,
+ 234426,
+ 17020,
+ 950,
+ 0,
+ 0,
+ 429,
+ 1245,
+ 405871,
+ 1097,
+ 280634,
+ 74,
+ 158233,
+ 1583,
+ 180333,
+ 42114,
+ 575973,
+ 539327,
+ 59252,
+ 121928,
+ 165,
+ 148501,
+ 55757,
+ 7494,
+ 127728,
+ 7832,
+ 68504,
+ 619770,
+ 70995,
+ 312816,
+ 7307,
+ 38265,
+ 46248,
+ 363304,
+ 269442,
+ 77112,
+ 448331,
+ 910442,
+ 474418,
+ 152752,
+ 752,
+ 104912,
+ 408492,
+ 691709,
+ 632381,
+ 48519,
+ 20524,
+ 344294,
+ 14670,
+ 0,
+ 21607,
+ 81162,
+ 181458,
+ 0,
+ 908322,
+ 7261,
+ 10888,
+ 58054,
+ 1788,
+ 970933,
+ 5925,
+ 121553,
+ 36152,
+ 588267,
+ 23615,
+ 1850,
+ 30728,
+ 3599,
+ 1319,
+ 6027,
+ 0,
+ 32141,
+ 984156,
+ 436781,
+ 15003,
+ 621407,
+ 9412,
+ 562911,
+ 189740,
+ 377895,
+ 656800,
+ 197,
+ 14413,
+ 99382,
+ 384,
+ 11480,
+ 0,
+ 86118,
+ 881961,
+ 1905,
+ 82061,
+ 4140,
+ 741153,
+ 26,
+ 687,
+ 12251,
+ 10945,
+ 209267,
+ 220602,
+ 135881,
+ 6,
+ 237945,
+ 158,
+ 5,
+ 76303,
+ 81344,
+ 986042,
+ 956063,
+ 30282,
+ 186055,
+ 357802,
+ 12492,
+ 577476,
+ 838,
+ 0,
+ 11,
+ 117602,
+ 0,
+ 187928,
+ 96860,
+ 4268,
+ 3478,
+ 818264,
+ 1649,
+ 17175,
+ 272,
+ 158951,
+ 440987,
+ 677594,
+ 14935,
+ 37953,
+ 0,
+ 198,
+ 160404,
+ 12,
+ 287803,
+ 2386,
+ 10,
+ 271663,
+ 319152,
+ 361322,
+ 68370,
+ 428,
+ 182707,
+ 387429,
+ 1152,
+ 360065,
+ 25218,
+ 2790,
+ 42228,
+ 13,
+ 110942,
+ 452491,
+ 1,
+ 665638,
+ 2308,
+ 1196,
+ 87306,
+ 66,
+ 219,
+ 0,
+ 130736,
+ 334,
+ 605,
+ 5979,
+ 2681,
+ 0,
+ 123463,
+ 11219,
+ 283681,
+ 19269,
+ 553,
+ 6217,
+ 130965,
+ 714409,
+ 242,
+ 674833,
+ 237581,
+ 133284,
+ 683,
+ 1758,
+ 278193,
+ 518726,
+ 44,
+ 420361,
+ 325228,
+ 14955,
+ 10,
+ 11994,
+ 64157,
+ 1937,
+ 20214,
+ 848,
+ 27804,
+ 151341,
+ 79236,
+ 316393,
+ 158883,
+ 1196,
+ 334,
+ 22797,
+ 185955,
+ 13857,
+ 397357,
+ 7948,
+ 6038,
+ 0,
+ 2621,
+ 16,
+ 155267,
+ 44809,
+ 9171,
+ 21328,
+ 12212,
+ 40200,
+ 2600,
+ 439,
+ 804014,
+ 10938,
+ 96135,
+ 43696,
+ 158715,
+ 4,
+ 284558,
+ 191,
+ 270254,
+ 7923,
+ 880603,
+ 21032,
+ 107700,
+ 172,
+ 700823,
+ 5613,
+ 78816,
+ 258290,
+ 214398,
+ 821856,
+ 295325,
+ 0,
+ 1,
+ 23559,
+ 63895,
+ 21249,
+ 717490,
+ 956952,
+ 944819,
+ 793,
+ 356,
+ 757716,
+ 111773,
+ 394826,
+ 25665,
+ 4358,
+ 640216,
+ 1152,
+ 37175,
+ 150192,
+ 106071,
+ 28992,
+ 67,
+ 1685,
+ 134242,
+ 2,
+ 102045,
+ 1457,
+ 419589,
+ 6789,
+ 677,
+ 94675,
+ 11300,
+ 2595,
+ 8,
+ 926535,
+ 265194,
+ 0,
+ 886048,
+ 246242,
+ 1494,
+ 191,
+ 169985,
+ 649765,
+ 0,
+ 201,
+ 1069,
+ 679163,
+ 16627,
+ 274639,
+ 84438,
+ 3,
+ 1301,
+ 247496,
+ 5879,
+ 710904,
+ 403652,
+ 958241,
+ 361,
+ 139732,
+ 6042,
+ 15985,
+ 2378,
+ 267031,
+ 223767,
+ 9656,
+ 241717,
+ 33863,
+ 14314,
+ 205697,
+ 1274,
+ 168000,
+ 621777,
+ 837913,
+ 89654,
+ 659829,
+ 69,
+ 503884,
+ 432717,
+ 70443,
+ 110891,
+ 19655,
+ 132432,
+ 620401,
+ 428,
+ 0,
+ 425662,
+ 0,
+ 0,
+ 0,
+ 194489,
+ 7601,
+ 26870,
+ 0,
+ 63,
+ 594,
+ 12278,
+ 582479,
+ 213723,
+ 424489,
+ 96446,
+ 990664,
+ 46966,
+ 44137,
+ 829810,
+ 104,
+ 19707,
+ 16,
+ 0,
+ 2499,
+ 167075,
+ 140972,
+ 249283,
+ 6620,
+ 68368,
+ 856414,
+ 9255,
+ 14315,
+ 0,
+ 11432,
+ 24329,
+ 216463,
+ 299556,
+ 818401,
+ 246607,
+ 697733,
+ 229,
+ 144,
+ 389394,
+ 664634,
+ 0,
+ 19393,
+ 657903,
+ 52912,
+ 952177,
+ 536931,
+ 187271,
+ 17687,
+ 970155,
+ 232571,
+ 234016,
+ 159980,
+ 13510,
+ 32952,
+ 0,
+ 0,
+ 24132,
+ 18806,
+ 15624,
+ 28364,
+ 472126,
+ 626978,
+ 599,
+ 112843,
+ 502933,
+ 915660,
+ 63920,
+ 0,
+ 84,
+ 10899,
+ 904823,
+ 126,
+ 469132,
+ 590052,
+ 195831,
+ 443113,
+ 294149,
+ 15944,
+ 2271,
+ 282974,
+ 211,
+ 0,
+ 22934,
+ 82283,
+ 49973,
+ 41707,
+ 87530,
+ 0,
+ 910528,
+ 0,
+ 36029,
+ 423337,
+ 817512,
+ 223671,
+ 27800,
+ 398847,
+ 198528,
+ 1,
+ 560679,
+ 518270,
+ 23033,
+ 501059,
+ 0,
+ 3909,
+ 272062,
+ 261581,
+ 187,
+ 52043,
+ 334,
+ 24354,
+ 3947,
+ 8549,
+ 37863,
+ 328851,
+ 963771,
+ 1,
+ 3930,
+ 82416,
+ 6,
+ 2943,
+ 122101,
+ 82577,
+ 85,
+ 89540,
+ 5135,
+ 109236,
+ 18297,
+ 1,
+ 177371,
+ 4541,
+ 769577,
+ 178,
+ 417,
+ 960566,
+ 33803,
+ 911651,
+ 248160,
+ 153725,
+ 43981,
+ 809174,
+ 116,
+ 486900,
+ 4842,
+ 148490,
+ 131534,
+ 4347,
+ 239949,
+ 984096,
+ 749756,
+ 429499,
+ 2794,
+ 78209,
+ 18812,
+ 21111,
+ 490,
+ 328042,
+ 12,
+ 132119,
+ 505103,
+ 353148,
+ 0,
+ 373656,
+ 951244,
+ 491,
+ 355778,
+ 30620,
+ 317,
+ 60175,
+ 220,
+ 214496,
+ 41249,
+ 5169,
+ 78367,
+ 506804,
+ 0,
+ 1368,
+ 407,
+ 295126,
+ 1288,
+ 86,
+ 97614,
+ 61640,
+ 244723,
+ 3,
+ 0,
+ 869827,
+ 527246,
+ 52,
+ 107036,
+ 240739,
+ 780281,
+ 113084,
+ 62009,
+ 740343,
+ 483201,
+ 8649,
+ 16419,
+ 1,
+ 801574,
+ 95524,
+ 326126,
+ 26912,
+ 877040,
+ 10262,
+ 5895,
+ 0,
+ 132633,
+ 59171,
+ 306347,
+ 702701,
+ 196245,
+ 12642,
+ 32723,
+ 24608,
+ 30287,
+ 45775,
+ 18281,
+ 7587,
+ 144532,
+ 5,
+ 35,
+ 99862,
+ 215127,
+ 170875,
+ 61461,
+ 77790,
+ 5,
+ 0,
+ 129358,
+ 0,
+ 105084,
+ 21399,
+ 42233,
+ 85397,
+ 480654,
+ 555988,
+ 89575,
+ 42346,
+ 20004,
+ 11102,
+ 21321,
+ 185,
+ 379267,
+ 849147,
+ 121514,
+ 3388,
+ 33662,
+ 12,
+ 164898,
+ 226,
+ 274,
+ 385003,
+ 365052,
+ 693376,
+ 41245,
+ 9010,
+ 41594,
+ 89835,
+ 10490,
+ 272,
+ 128437,
+ 0,
+ 122648,
+ 277,
+ 116505,
+ 38372,
+ 4,
+ 1376,
+ 0,
+ 46317,
+ 139368,
+ 36398,
+ 193899,
+ 30632,
+ 26371,
+ 7548,
+ 367643,
+ 954849,
+ 25889,
+ 36567,
+ 176,
+ 140631,
+ 4690,
+ 975031,
+ 80965,
+ 500471,
+ 8442,
+ 43,
+ 27758,
+ 301501,
+ 3797,
+ 80,
+ 384440,
+ 928477,
+ 4960,
+ 24566,
+ 33245,
+ 14638,
+ 228354,
+ 54347,
+ 861285,
+ 12841,
+ 2,
+ 157402,
+ 646747,
+ 53763,
+ 1,
+ 214732,
+ 49471,
+ 49757,
+ 998,
+ 201135,
+ 566,
+ 73512,
+ 194240,
+ 391773,
+ 21510,
+ 13,
+ 829894,
+ 783200,
+ 565329,
+ 2101,
+ 12,
+ 191043,
+ 1621,
+ 18443,
+ 279,
+ 294135,
+ 526503,
+ 729735,
+ 4639,
+ 444138,
+ 5835,
+ 12372,
+ 46362,
+ 1543,
+ 870907,
+ 83262,
+ 0,
+ 38331,
+ 95,
+ 1194,
+ 909,
+ 8053,
+ 453066,
+ 845561,
+ 411,
+ 3229,
+ 1,
+ 158,
+ 1431,
+ 835137,
+ 21774,
+ 7298,
+ 148388,
+ 224649,
+ 379318,
+ 520138,
+ 39781,
+ 172130,
+ 362634,
+ 487495,
+ 51957,
+ 158,
+ 1770,
+ 7,
+ 18010,
+ 1063,
+ 171484,
+ 19924,
+ 279867,
+ 469956,
+ 189785,
+ 0,
+ 814,
+ 60580,
+ 944349,
+ 18743,
+ 553235,
+ 0,
+ 95475,
+ 99,
+ 0,
+ 5,
+ 42623,
+ 178418,
+ 398940,
+ 5700,
+ 69023,
+ 5786,
+ 0,
+ 10531,
+ 551,
+ 86308,
+ 63451,
+ 32704,
+ 176903,
+ 0,
+ 251689,
+ 11589,
+ 25711,
+ 43437,
+ 1431,
+ 304,
+ 52965,
+ 34816,
+ 268688,
+ 47756,
+ 825323,
+ 122608,
+ 81246,
+ 69974,
+ 360515,
+ 99973,
+ 143015,
+ 5063,
+ 4499,
+ 34459,
+ 171982,
+ 677943,
+ 489082,
+ 257515,
+ 3765,
+ 5,
+ 7416,
+ 602206,
+ 74122,
+ 3,
+ 686204,
+ 5493,
+ 28901,
+ 11349,
+ 549668,
+ 257082,
+ 82000,
+ 17031,
+ 1517,
+ 7442,
+ 937160,
+ 722,
+ 0,
+ 72952,
+ 377192,
+ 438266,
+ 555,
+ 31436,
+ 284,
+ 56390,
+ 0,
+ 585856,
+ 27635,
+ 519344,
+ 126131,
+ 360273,
+ 845073,
+ 0,
+ 191965,
+ 55652,
+ 23,
+ 112773,
+ 639025,
+ 84749,
+ 0,
+ 330822,
+ 7173,
+ 126217,
+ 871,
+ 112112,
+ 0,
+ 664,
+ 530474,
+ 1,
+ 379564,
+ 172617,
+ 647308,
+ 0,
+ 356,
+ 17,
+ 84345,
+ 457,
+ 0,
+ 8,
+ 6,
+ 136602,
+ 634424,
+ 0,
+ 177298,
+ 100726,
+ 91661,
+ 383792,
+ 1665,
+ 43583,
+ 15775,
+ 4083,
+ 4277,
+ 345749,
+ 969599,
+ 65804,
+ 19327,
+ 0,
+ 352514,
+ 4225,
+ 9,
+ 103767,
+ 0,
+ 0,
+ 148436,
+ 850,
+ 33,
+ 2146,
+ 20153,
+ 50,
+ 9063,
+ 50329,
+ 348379,
+ 2569,
+ 83697,
+ 37073,
+ 715486,
+ 629,
+ 4753,
+ 442,
+ 259203,
+ 287223,
+ 48625,
+ 9,
+ 70184,
+ 45946,
+ 144947,
+ 0,
+ 60285,
+ 28640,
+ 7626,
+ 134159,
+ 33,
+ 12452,
+ 150566,
+ 348293,
+ 124426,
+ 353952,
+ 11,
+ 22,
+ 776742,
+ 29072,
+ 132168,
+ 254533,
+ 319957,
+ 1602,
+ 1659,
+ 209341,
+ 32847,
+ 92392,
+ 753005,
+ 1392,
+ 10271,
+ 28557,
+ 6717,
+ 941745,
+ 0,
+ 0,
+ 0,
+ 78645,
+ 45320,
+ 11193,
+ 1448,
+ 130626,
+ 377907,
+ 795535,
+ 24285,
+ 26094,
+ 266691,
+ 64449,
+ 77400,
+ 191410,
+ 1,
+ 1346,
+ 25224,
+ 489637,
+ 47052,
+ 248592,
+ 76689,
+ 0,
+ 7722,
+ 47285,
+ 3152,
+ 285577,
+ 0,
+ 149366,
+ 264346,
+ 1,
+ 208602,
+ 320459,
+ 131771,
+ 1421,
+ 350,
+ 723283,
+ 714934,
+ 0,
+ 566439,
+ 11656,
+ 34189,
+ 125484,
+ 943273,
+ 15,
+ 7789,
+ 0,
+ 7427,
+ 464278,
+ 680924,
+ 651102,
+ 87794,
+ 39640,
+ 838644,
+ 964500,
+ 1,
+ 1765,
+ 272604,
+ 10,
+ 837347,
+ 44845,
+ 130,
+ 163357,
+ 4150,
+ 403331,
+ 839132,
+ 44876,
+ 272792,
+ 592527,
+ 57225,
+ 128826,
+ 2915,
+ 2,
+ 3570,
+ 2410,
+ 199,
+ 171358,
+ 5931,
+ 53620,
+ 55299,
+ 1868,
+ 24123,
+ 165,
+ 346513,
+ 16527,
+ 133,
+ 517412,
+ 195700,
+ 730365,
+ 896209,
+ 152760,
+ 24577,
+ 65,
+ 8218,
+ 349642,
+ 901345,
+ 5127,
+ 5102,
+ 238318,
+ 955,
+ 631921,
+ 12218,
+ 55101,
+ 930381,
+ 219503,
+ 469237,
+ 132,
+ 16701,
+ 494,
+ 199729,
+ 0,
+ 32139,
+ 314,
+ 172,
+ 2947,
+ 106997,
+ 4871,
+ 236,
+ 6146,
+ 1843,
+ 128,
+ 0,
+ 254240,
+ 2964,
+ 14825,
+ 60624,
+ 2108,
+ 286953,
+ 654931,
+ 0,
+ 0,
+ 396587,
+ 19852,
+ 70311,
+ 363561,
+ 282,
+ 17966,
+ 924254,
+ 104173,
+ 130816,
+ 179096,
+ 105466,
+ 136,
+ 618261,
+ 358433,
+ 25587,
+ 49357,
+ 102,
+ 133746,
+ 620776,
+ 17084,
+ 406881,
+ 802675,
+ 349,
+ 69,
+ 8761,
+ 278482,
+ 16336,
+ 128,
+ 160096,
+ 25857,
+ 280,
+ 39639,
+ 726299,
+ 293905,
+ 4621,
+ 41,
+ 649,
+ 3655,
+ 269286,
+ 578026,
+ 0,
+ 11156,
+ 1,
+ 744858,
+ 531,
+ 48155,
+ 28435,
+ 7991,
+ 447,
+ 10201,
+ 379341,
+ 0,
+ 5773,
+ 0,
+ 295,
+ 228592,
+ 331155,
+ 104089,
+ 628069,
+ 29693,
+ 22,
+ 13,
+ 0,
+ 0,
+ 554349,
+ 6082,
+ 238,
+ 23,
+ 151873,
+ 805937,
+ 0,
+ 194076,
+ 6450,
+ 3,
+ 128322,
+ 69149,
+ 95511,
+ 86,
+ 844368,
+ 415964,
+ 51985,
+ 308686,
+ 553403,
+ 624943,
+ 365800,
+ 4,
+ 120263,
+ 91239,
+ 195248,
+ 58010,
+ 19,
+ 415112,
+ 136806,
+ 42,
+ 571848,
+ 55306,
+ 29454,
+ 3,
+ 144926,
+ 189,
+ 0,
+ 161943,
+ 592155,
+ 10930,
+ 279297,
+ 56932,
+ 957430,
+ 10244,
+ 190296,
+ 807209,
+ 781,
+ 1466,
+ 235055,
+ 33,
+ 196,
+ 58280,
+ 436,
+ 408649,
+ 221,
+ 711143,
+ 10495,
+ 2441,
+ 275720,
+ 2,
+ 15391,
+ 132107,
+ 102610,
+ 688549,
+ 237142,
+ 3041,
+ 14,
+ 308623,
+ 0,
+ 0,
+ 287,
+ 295147,
+ 61443,
+ 229,
+ 207,
+ 2051,
+ 64,
+ 13479,
+ 55656,
+ 570134,
+ 50387,
+ 225869,
+ 20615,
+ 258465,
+ 64932,
+ 112461,
+ 164521,
+ 907269,
+ 758563,
+ 22901,
+ 0,
+ 7944,
+ 48,
+ 154921,
+ 2784,
+ 548608,
+ 0,
+ 12524,
+ 142556,
+ 0,
+ 13882,
+ 507227,
+ 316598,
+ 987551,
+ 0,
+ 894687,
+ 1964,
+ 364,
+ 10316,
+ 440269,
+ 9,
+ 776723,
+ 72288,
+ 54604,
+ 185101,
+ 142,
+ 362,
+ 11679,
+ 77,
+ 79,
+ 529321,
+ 364,
+ 42387,
+ 0,
+ 570879,
+ 417503,
+ 604871,
+ 578806,
+ 1102,
+ 66584,
+ 615440,
+ 146744,
+ 19441,
+ 170478,
+ 144069,
+ 36170,
+ 145376,
+ 842283,
+ 193612,
+ 3,
+ 359429,
+ 368596,
+ 0,
+ 11064,
+ 7726,
+ 229410,
+ 63569,
+ 67402,
+ 91,
+ 203201,
+ 213513,
+ 0,
+ 704479,
+ 1325,
+ 0,
+ 385154,
+ 13,
+ 806763,
+ 197132,
+ 6183,
+ 45760,
+ 99377,
+ 0,
+ 972077,
+ 4043,
+ 195700,
+ 34229,
+ 0,
+ 154027,
+ 633,
+ 6,
+ 32142,
+ 0,
+ 29,
+ 620842,
+ 14099,
+ 495465,
+ 26937,
+ 0,
+ 0,
+ 432,
+ 227704,
+ 0,
+ 63,
+ 0,
+ 19,
+ 863491,
+ 20,
+ 1,
+ 160713,
+ 24607,
+ 85800,
+ 3566,
+ 37854,
+ 81913,
+ 121573,
+ 816,
+ 20,
+ 133253,
+ 692231,
+ 4869,
+ 255175,
+ 15028,
+ 9383,
+ 542877,
+ 4608,
+ 369610,
+ 243635,
+ 385285,
+ 391565,
+ 286009,
+ 0,
+ 61685,
+ 416318,
+ 208,
+ 67019,
+ 788416,
+ 88,
+ 165056,
+ 0,
+ 439589,
+ 160,
+ 105528,
+ 152,
+ 160624,
+ 865,
+ 390229,
+ 714086,
+ 6007,
+ 30229,
+ 481306,
+ 173266,
+ 1135,
+ 2266,
+ 8,
+ 59,
+ 104722,
+ 647885,
+ 579471,
+ 21309,
+ 230834,
+ 140278,
+ 31858,
+ 3288,
+ 36011,
+ 151387,
+ 594217,
+ 22439,
+ 418638,
+ 76859,
+ 29363,
+ 154809,
+ 275533,
+ 39,
+ 472996,
+ 22076,
+ 7481,
+ 155705,
+ 10406,
+ 214779,
+ 223,
+ 1312,
+ 16391,
+ 17203,
+ 55605,
+ 44579,
+ 69332,
+ 303,
+ 19217,
+ 26288,
+ 126212,
+ 316,
+ 98,
+ 114,
+ 37382,
+ 137591,
+ 439749,
+ 12972,
+ 54,
+ 154879,
+ 0,
+ 102680,
+ 7639,
+ 309119,
+ 263550,
+ 766,
+ 1124,
+ 56,
+ 686608,
+ 123767,
+ 518054,
+ 18,
+ 672385,
+ 3161,
+ 53791,
+ 26769,
+ 451670,
+ 61,
+ 148245,
+ 2713,
+ 96725,
+ 4794,
+ 33247,
+ 297946,
+ 33380,
+ 0,
+ 20034,
+ 5647,
+ 17227,
+ 76444,
+ 0,
+ 21011,
+ 675,
+ 13226,
+ 1027,
+ 990842,
+ 124459,
+ 34406,
+ 53,
+ 69540,
+ 134,
+ 0,
+ 168521,
+ 6,
+ 4075,
+ 1137,
+ 63740,
+ 220,
+ 10434,
+ 1171,
+ 28950,
+ 0,
+ 79680,
+ 993269,
+ 355622,
+ 15,
+ 0,
+ 1452,
+ 21667,
+ 22208,
+ 494484,
+ 33984,
+ 691308,
+ 10,
+ 693686,
+ 196,
+ 9,
+ 70676,
+ 157660,
+ 775,
+ 165,
+ 468432,
+ 1083,
+ 515154,
+ 778344,
+ 70241,
+ 42,
+ 40931,
+ 277125,
+ 43837,
+ 301881,
+ 1332,
+ 56712,
+ 9013,
+ 1299,
+ 7564,
+ 31092,
+ 1975,
+ 113517,
+ 833295,
+ 245021,
+ 36503,
+ 23586,
+ 149327,
+ 89175,
+ 10512,
+ 484348,
+ 187793,
+ 954609,
+ 53199,
+ 792175,
+ 126,
+ 12369,
+ 405,
+ 0,
+ 6614,
+ 322857,
+ 166,
+ 571874,
+ 60839,
+ 180975,
+ 146722,
+ 411565,
+ 1536,
+ 1,
+ 11,
+ 116230,
+ 60514,
+ 9003,
+ 2325,
+ 43763,
+ 63,
+ 355553,
+ 0,
+ 389876,
+ 14672,
+ 11526,
+ 160209,
+ 65,
+ 10283,
+ 966,
+ 10,
+ 58333,
+ 129920,
+ 2850,
+ 83346,
+ 0,
+ 14,
+ 295819,
+ 679550,
+ 143928,
+ 29489,
+ 82324,
+ 36558,
+ 267118,
+ 143313,
+ 90107,
+ 12789,
+ 951,
+ 0,
+ 187619,
+ 295317,
+ 82,
+ 41326,
+ 309682,
+ 907327,
+ 809358,
+ 324,
+ 139157,
+ 12,
+ 78366,
+ 671811,
+ 354,
+ 131,
+ 70525,
+ 35830,
+ 281018,
+ 91456,
+ 92523,
+ 54874,
+ 48273,
+ 2423,
+ 0,
+ 81,
+ 361314,
+ 374811,
+ 394758,
+ 15350,
+ 795,
+ 3,
+ 16779,
+ 796684,
+ 477556,
+ 73927,
+ 26643,
+ 119281,
+ 62692,
+ 17039,
+ 454778,
+ 952,
+ 48973,
+ 19529,
+ 151,
+ 239121,
+ 93509,
+ 254702,
+ 1307,
+ 10029,
+ 7973,
+ 546706,
+ 806644,
+ 680517,
+ 223,
+ 0,
+ 2,
+ 0,
+ 402421,
+ 619193,
+ 15685,
+ 2,
+ 939715,
+ 519198,
+ 0,
+ 444312,
+ 23204,
+ 35669,
+ 32467,
+ 0,
+ 799725,
+ 5883,
+ 2217,
+ 32292,
+ 355557,
+ 22179,
+ 1066,
+ 15704,
+ 610,
+ 37819,
+ 403626,
+ 83101,
+ 10989,
+ 311607,
+ 43394,
+ 72576,
+ 335450,
+ 85964,
+ 73734,
+ 105142,
+ 38292,
+ 0,
+ 181516,
+ 33959,
+ 611797,
+ 221838,
+ 5931,
+ 7666,
+ 1044,
+ 477173,
+ 13591,
+ 405,
+ 521,
+ 190653,
+ 184191,
+ 0,
+ 215,
+ 847195,
+ 22782,
+ 11912,
+ 27345,
+ 2572,
+ 0,
+ 566350,
+ 7,
+ 52302,
+ 26641,
+ 587826,
+ 127,
+ 2,
+ 44449,
+ 153198,
+ 14,
+ 926,
+ 285,
+ 0,
+ 938196,
+ 52255,
+ 9153,
+ 807,
+ 12548,
+ 358324,
+ 18521,
+ 104956,
+ 42738,
+ 116,
+ 135772,
+ 189554,
+ 38,
+ 54,
+ 36,
+ 89768,
+ 17170,
+ 75,
+ 34502,
+ 45489,
+ 172796,
+ 971810,
+ 16153,
+ 499280,
+ 1,
+ 879663,
+ 53830,
+ 186,
+ 539,
+ 242059,
+ 268,
+ 402,
+ 2732,
+ 68057,
+ 18463,
+ 198560,
+ 10068,
+ 591753,
+ 6116,
+ 699280,
+ 1,
+ 0,
+ 114258,
+ 277,
+ 149,
+ 283821,
+ 352561,
+ 88172,
+ 684476,
+ 3450,
+ 87,
+ 99936,
+ 3155,
+ 72983,
+ 31619,
+ 8832,
+ 58666,
+ 0,
+ 59023,
+ 306091,
+ 352150,
+ 255063,
+ 992708,
+ 23,
+ 4896,
+ 18165,
+ 424401,
+ 227613,
+ 5175,
+ 347,
+ 139846,
+ 11962,
+ 714,
+ 3501,
+ 82367,
+ 11110,
+ 10,
+ 12874,
+ 0,
+ 0,
+ 222712,
+ 169,
+ 123281,
+ 0,
+ 268149,
+ 101,
+ 17446,
+ 4262,
+ 489,
+ 0,
+ 30,
+ 0,
+ 277235,
+ 28,
+ 71,
+ 23,
+ 61219,
+ 953631,
+ 477548,
+ 662491,
+ 273,
+ 44787,
+ 4130,
+ 14483,
+ 470571,
+ 735977,
+ 406648,
+ 815898,
+ 5985,
+ 462696,
+ 937510,
+ 9,
+ 0,
+ 111727,
+ 93,
+ 331435,
+ 336402,
+ 78690,
+ 49,
+ 0,
+ 87422,
+ 1242,
+ 0,
+ 8783,
+ 8540,
+ 314,
+ 33411,
+ 805718,
+ 247,
+ 6870,
+ 523743,
+ 8323,
+ 612593,
+ 430,
+ 354048,
+ 264913,
+ 83,
+ 114063,
+ 202825,
+ 35202,
+ 32823,
+ 185554,
+ 85760,
+ 45159,
+ 5971,
+ 267733,
+ 4545,
+ 116,
+ 6910,
+ 24833,
+ 218,
+ 922362,
+ 221735,
+ 740,
+ 7112,
+ 31,
+ 15739,
+ 523589,
+ 4,
+ 95996,
+ 936,
+ 823951,
+ 0,
+ 88,
+ 160,
+ 375419,
+ 663627,
+ 3741,
+ 22896,
+ 114326,
+ 415962,
+ 880100,
+ 6222,
+ 18650,
+ 35524,
+ 195076,
+ 506,
+ 451640,
+ 541336,
+ 70903,
+ 3946,
+ 1,
+ 61765,
+ 1,
+ 2696,
+ 753129,
+ 289,
+ 225234,
+ 378692,
+ 1703,
+ 6751,
+ 1,
+ 820,
+ 7677,
+ 589,
+ 12412,
+ 317,
+ 69,
+ 226031,
+ 134523,
+ 318253,
+ 66677,
+ 111025,
+ 96,
+ 0,
+ 96,
+ 523528,
+ 1017,
+ 0,
+ 258740,
+ 420947,
+ 4600,
+ 400684,
+ 12174,
+ 11770,
+ 52,
+ 5959,
+ 82658,
+ 531787,
+ 202,
+ 548430,
+ 964,
+ 1054,
+ 34,
+ 96897,
+ 25445,
+ 47609,
+ 386052,
+ 97004,
+ 1935,
+ 30074,
+ 13458,
+ 494105,
+ 54,
+ 65575,
+ 594698,
+ 2340,
+ 20259,
+ 84,
+ 2774,
+ 534,
+ 972534,
+ 115057,
+ 0,
+ 11379,
+ 0,
+ 271,
+ 266305,
+ 132595,
+ 2,
+ 773561,
+ 52365,
+ 3585,
+ 351,
+ 148206,
+ 778964,
+ 149379,
+ 596,
+ 284914,
+ 2900,
+ 35596,
+ 1547,
+ 212027,
+ 8100,
+ 12248,
+ 3013,
+ 1814,
+ 183415,
+ 273633,
+ 15812,
+ 0,
+ 966680,
+ 14830,
+ 134309,
+ 0,
+ 416450,
+ 206611,
+ 816,
+ 82258,
+ 9873,
+ 3155,
+ 53485,
+ 779805,
+ 107690,
+ 254475,
+ 102504,
+ 72495,
+ 17301,
+ 472130,
+ 6895,
+ 245420,
+ 7299,
+ 110508,
+ 27776,
+ 246134,
+ 0,
+ 330853,
+ 0,
+ 271767,
+ 61886,
+ 24123,
+ 309681,
+ 58325,
+ 608865,
+ 20666,
+ 87349,
+ 229228,
+ 246,
+ 457768,
+ 5374,
+ 69643,
+ 148,
+ 618375,
+ 45236,
+ 352565,
+ 133904,
+ 152,
+ 10688,
+ 18,
+ 0,
+ 276036,
+ 493281,
+ 11156,
+ 12566,
+ 5762,
+ 113,
+ 24179,
+ 98,
+ 327,
+ 893,
+ 209180,
+ 140805,
+ 0,
+ 2341,
+ 66309,
+ 30305,
+ 630559,
+ 3682,
+ 152767,
+ 265822,
+ 142868,
+ 1535,
+ 728603,
+ 69081,
+ 353151,
+ 237995,
+ 1075,
+ 925071,
+ 86,
+ 6748,
+ 0,
+ 684186,
+ 735,
+ 13793,
+ 4790,
+ 73175,
+ 69677,
+ 367627,
+ 238650,
+ 303543,
+ 1,
+ 26059,
+ 21392,
+ 10,
+ 288609,
+ 0,
+ 76345,
+ 158496,
+ 7000,
+ 1865,
+ 20385,
+ 0,
+ 54213,
+ 9948,
+ 102667,
+ 6963,
+ 71,
+ 555744,
+ 5626,
+ 2512,
+ 1124,
+ 7171,
+ 628,
+ 29225,
+ 321687,
+ 61519,
+ 4,
+ 8352,
+ 9156,
+};
+
+char *pointers[NCYCLES];
+
+int main(void)
+{
+ int r, i, j, sp, sq;
+ char *p, *q, *ep, *eq;
+ int ok;
+ int err = 0;
+
+ for (r = 0; r < 4; r++) {
+ for (i = 0; i < NCYCLES; i++) {
+ pointers[i] = p = malloc(sp = sizes[i]);
+ ep = p + sp;
+ ok = 1;
+ for (j = 0; j < i; j++) {
+ q = pointers[j];
+ sq = sizes[j];
+ eq = q + sq;
+
+ if ((p < q && ep > q) || (p >= q && p < eq)) {
+ ok = 0;
+ err = 1;
+ break;
+ }
+ }
+ printf("Allocated %6d bytes at %p, ok = %d\n", sp, p,
+ ok);
+
+ if (p)
+ memset(p, 0xee, sp); /* Poison this memory */
+ }
+
+ for (i = 0; i < NCYCLES; i++) {
+ free(pointers[i]);
+ printf("Freed %6d bytes at %p\n", sizes[i],
+ pointers[i]);
+ }
+ }
+
+ return err;
+}
diff --git a/usr/klibc/tests/malloctest2.c b/usr/klibc/tests/malloctest2.c
new file mode 100644
index 0000000..1845073
--- /dev/null
+++ b/usr/klibc/tests/malloctest2.c
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define NCYCLES 32768
+#define NSLOTS 4096
+
+struct slot {
+ char *ptr;
+ size_t size;
+};
+
+struct slot s[NSLOTS];
+
+int main(void)
+{
+ size_t sp, sq;
+ char *p, *ep, *q, *eq;
+ int r, i, j;
+ int ok;
+ int err = 0;
+
+ for (r = 0; r < NCYCLES; r++) {
+ i = lrand48() % NSLOTS;
+
+ if (s[i].ptr) {
+ free(s[i].ptr);
+ printf("Freed %8zu bytes at %p\n", s[i].size,
+ s[i].ptr);
+ s[i].ptr = NULL;
+ s[i].size = 0;
+ } else {
+ sp = lrand48(); /* 32-bit random number */
+ sp >>= 12 + (lrand48() % 20);
+
+ s[i].size = sp;
+ s[i].ptr = p = malloc(sp);
+ ep = p + sp;
+ ok = 1;
+ for (j = 0; j < NSLOTS; j++) {
+ q = s[j].ptr;
+ if (i != j && q) {
+ sq = s[j].size;
+ eq = q + sq;
+
+ if ((p < q && ep > q)
+ || (p >= q && p < eq)) {
+ ok = 0;
+ err = 1;
+ break;
+ }
+ }
+ }
+ printf("Allocated %8zu bytes at %p, ok = %d\n", sp, p,
+ ok);
+
+ if (p)
+ memset(p, 0xee, sp); /* Poison this memory */
+ }
+ }
+ return err;
+}
diff --git a/usr/klibc/tests/malloctest3.c b/usr/klibc/tests/malloctest3.c
new file mode 100644
index 0000000..d9d2ca9
--- /dev/null
+++ b/usr/klibc/tests/malloctest3.c
@@ -0,0 +1,57 @@
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ void *p;
+
+ /* Our implementation should always return NULL */
+ errno = 0;
+ p = malloc(0);
+ assert(p == NULL);
+ assert(errno == 0);
+
+ /* These sizes won't fit in memory, so should always fail */
+ errno = 0;
+ p = malloc(SIZE_MAX);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+ errno = 0;
+ p = malloc(SIZE_MAX - 0x10000);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+
+#if SIZE_MAX > 0x100000000
+ /* We should be able to allocate 4 GB + 1 */
+ p = malloc(0x100000001);
+ assert(p != NULL);
+ ((volatile char *)p)[0x100000000] = 1;
+ free(p);
+
+ /* calloc() should detect multiplication overflow */
+ errno = 0;
+ p = calloc(0x100000000, 0x100000000);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+ errno = 0;
+ p = calloc(0x100000001, 0x100000001);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+#else
+ /* calloc() should detect multiplication overflow */
+ errno = 0;
+ p = calloc(0x10000, 0x10000);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+ errno = 0;
+ p = calloc(0x10001, 0x10001);
+ assert(p == NULL);
+ assert(errno == ENOMEM);
+#endif
+
+ return 0;
+}
diff --git a/usr/klibc/tests/memstrtest.c b/usr/klibc/tests/memstrtest.c
new file mode 100644
index 0000000..8d473fb
--- /dev/null
+++ b/usr/klibc/tests/memstrtest.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+ unsigned char t1[256], t2[256];
+ int i;
+ int r;
+
+ for (i = 0; i < (int)sizeof(t1); i++)
+ t1[i] = t2[i] = (unsigned char)i;
+
+ r = memcmp(t1, t2, sizeof(t1));
+ printf("memcmp r = %d\n", r);
+ r = memcmp(t1, t2, sizeof(t1) / 2);
+ printf("memcmp r = %d\n", r);
+ t1[255] = 0;
+ r = memcmp(t1, t2, sizeof(t1));
+ printf("memcmp r = %d\n", r);
+
+ for (i = 0; i < (int)sizeof(t1); i++)
+ t1[i] = 0xaa;
+ memset(t2, 0xaa, sizeof(t2));
+ r = memcmp(t1, t2, sizeof(t1));
+ printf("memcmp r = %d\n", r);
+ return 0;
+}
diff --git a/usr/klibc/tests/microhello.c b/usr/klibc/tests/microhello.c
new file mode 100644
index 0000000..c999d11
--- /dev/null
+++ b/usr/klibc/tests/microhello.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void)
+{
+ static const char hello[] = "Hello, World!\n";
+ _fwrite(hello, sizeof hello - 1, stdout);
+ return 0;
+}
diff --git a/usr/klibc/tests/minihello.c b/usr/klibc/tests/minihello.c
new file mode 100644
index 0000000..ae9072e
--- /dev/null
+++ b/usr/klibc/tests/minihello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(void)
+{
+ fputs("Hello, World!\n", stdout);
+ return 0;
+}
diff --git a/usr/klibc/tests/mmaptest.c b/usr/klibc/tests/mmaptest.c
new file mode 100644
index 0000000..eac04e8
--- /dev/null
+++ b/usr/klibc/tests/mmaptest.c
@@ -0,0 +1,73 @@
+/*
+ * mmaptest.c
+ *
+ * Test some simple cases of mmap()
+ */
+
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+static void make_test_file(int fd)
+{
+ unsigned long v;
+ FILE *f = fdopen(fd, "wb");
+
+ for (v = 0; v < 262144; v += sizeof(v))
+ _fwrite(&v, sizeof(v), f);
+}
+
+int main(int argc, char *argv[])
+{
+ void *foo;
+ char *test_file = (argc > 1) ? argv[1] : "/tmp/mmaptest.tmp";
+ int rv, fd;
+
+ /* Important case, this is how we get memory for malloc() */
+ errno = 0;
+ foo = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+
+ printf("mmap() returned %p, errno = %d\n", foo, errno);
+ if (foo == MAP_FAILED)
+ return 1;
+
+ rv = munmap(foo, 65536);
+ printf("munmap() returned %d, errno = %d\n", rv, errno);
+ if (rv)
+ return 1;
+
+ /* Create test file */
+ fd = open(test_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ perror(test_file);
+ return 1;
+ }
+
+ make_test_file(fd);
+
+ /* Map test file */
+ foo = mmap(NULL, 65536, PROT_READ, MAP_SHARED, fd, 131072);
+ printf("mmap() returned %p, errno = %d\n", foo, errno);
+ if (foo == MAP_FAILED)
+ return 1;
+
+ if (*(unsigned long *)foo != 131072) {
+ printf("mmap() with offset returned the wrong offset %ld!\n",
+ *(unsigned long *)foo);
+ return 1;
+ }
+
+ if (munmap(foo, 65536)) {
+ printf("munmap() returned nonzero, errno = %d\n", errno);
+ return 1;
+ }
+
+ close(fd);
+ unlink(test_file);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/opentest.c b/usr/klibc/tests/opentest.c
new file mode 100644
index 0000000..8be7b3d
--- /dev/null
+++ b/usr/klibc/tests/opentest.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main(void)
+{
+ char buffer[1024];
+ FILE *f;
+
+ f = fopen("/etc/passwd", "r");
+ fgets(buffer, 1024, f);
+ fclose(f);
+
+ printf("Line 1 = %s", buffer);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/pipetest.c b/usr/klibc/tests/pipetest.c
new file mode 100644
index 0000000..0e49721
--- /dev/null
+++ b/usr/klibc/tests/pipetest.c
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+int main(void)
+{
+ /* Size of message must be <= PIPE_BUF */
+ const char msg[] = "Hello, World!";
+ char buf[512];
+ int rv;
+ int pfd[2];
+
+ if (pipe(pfd)) {
+ perror("pipe");
+ return 1;
+ }
+
+ if (write(pfd[1], msg, sizeof msg) != sizeof msg) {
+ perror("write");
+ return 1;
+ }
+
+ while ((rv = read(pfd[0], buf, sizeof buf)) < sizeof msg) {
+ if (rv == -1 && errno == EINTR)
+ continue;
+ perror("read");
+ return 1;
+ }
+
+ if (memcmp(msg, buf, sizeof msg)) {
+ fprintf(stderr, "Message miscompare!\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/tests/rtsig.c b/usr/klibc/tests/rtsig.c
new file mode 100644
index 0000000..a7f8eed
--- /dev/null
+++ b/usr/klibc/tests/rtsig.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <signal.h>
+
+int main(void)
+{
+#ifdef SIGRTMIN
+ printf("sigrtmin = %d, sigrtmax = %d\n", SIGRTMIN, SIGRTMAX);
+#else
+ printf("No realtime signals\n");
+#endif
+ return 0;
+}
diff --git a/usr/klibc/tests/select.c b/usr/klibc/tests/select.c
new file mode 100644
index 0000000..ba08112
--- /dev/null
+++ b/usr/klibc/tests/select.c
@@ -0,0 +1,55 @@
+/*
+ * Simple test of select()
+ */
+
+#include <sys/select.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ int fdn, fdz, pfd[2], rv;
+ fd_set readset;
+ struct timeval timeout;
+ int err = 0;
+
+ /* We can always read from /dev/zero; open a pipe that is never
+ ready for a "never readable" file descriptor */
+ fdz = open("/dev/zero", O_RDONLY);
+ pipe(pfd);
+ fdn = pfd[0];
+
+ FD_ZERO(&readset);
+ FD_SET(fdn, &readset);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+
+ rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+
+ if (rv != 0) {
+ fprintf(stderr,
+ "select with timeout failed (rv = %d, errno = %s)\n",
+ rv, strerror(errno));
+ err++;
+ }
+
+ FD_ZERO(&readset);
+ FD_SET(fdn, &readset);
+ FD_SET(fdz, &readset);
+
+ rv = select(FD_SETSIZE, &readset, NULL, NULL, &timeout);
+
+ if (rv != 1 || !FD_ISSET(fdz, &readset) ||
+ FD_ISSET(fdn, &readset)) {
+ fprintf(stderr,
+ "select with /dev/zero failed (rv = %d, errno = %s)\n",
+ rv, strerror(errno));
+ err++;
+ }
+
+ return err;
+}
diff --git a/usr/klibc/tests/setenvtest.c b/usr/klibc/tests/setenvtest.c
new file mode 100644
index 0000000..1b07199
--- /dev/null
+++ b/usr/klibc/tests/setenvtest.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ (void)argc;
+ (void)argv;
+
+ /* Set SETENV */
+ setenv("SETENV", "setenv", 1);
+
+ /* Set PUTENV */
+ putenv("PUTENV=putenv");
+
+ /* Print the results... */
+ printf("SETENV = %s\n", getenv("SETENV"));
+ printf("PUTENV = %s\n", getenv("PUTENV"));
+
+ /* Override tests */
+ setenv("SETENV", "setenv_good", 1);
+ putenv("PUTENV=putenv_good");
+ printf("SETENV = %s\n", getenv("SETENV"));
+ printf("PUTENV = %s\n", getenv("PUTENV"));
+
+ /* Non-override test */
+ setenv("SETENV", "setenv_bad", 0);
+ setenv("NEWENV", "newenv_good", 0);
+ printf("SETENV = %s\n", getenv("SETENV"));
+ printf("NEWENV = %s\n", getenv("NEWENV"));
+
+ /* Undef test */
+ unsetenv("SETENV");
+ unsetenv("NEWENV");
+ printf("SETENV = %s\n", getenv("SETENV"));
+ printf("NEWENV = %s\n", getenv("NEWENV"));
+
+ return 0;
+}
diff --git a/usr/klibc/tests/setjmptest.c b/usr/klibc/tests/setjmptest.c
new file mode 100644
index 0000000..fd9cb1c
--- /dev/null
+++ b/usr/klibc/tests/setjmptest.c
@@ -0,0 +1,37 @@
+/*
+ * setjmptest.c
+ */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+static jmp_buf buf;
+
+void do_stuff(int v)
+{
+ printf("calling longjmp with %d... ", v + 1);
+ longjmp(buf, v + 1);
+}
+
+void recurse(int ctr, int v)
+{
+ if (ctr--)
+ recurse(ctr, v);
+ else
+ do_stuff(v);
+
+ printf("ERROR!\n"); /* We should never get here... */
+}
+
+int main(void)
+{
+ int v;
+
+ v = setjmp(buf);
+ printf("setjmp returned %d\n", v);
+
+ if (v < 256)
+ recurse(v, v);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/sig-nodefer.c b/usr/klibc/tests/sig-nodefer.c
new file mode 100644
index 0000000..90086e4
--- /dev/null
+++ b/usr/klibc/tests/sig-nodefer.c
@@ -0,0 +1,55 @@
+/*
+ * Expected output of ./sig-nodefer:
+ * SIGUSR2: blocked
+ * SIGTERM: blocked
+ */
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void handler(int signum)
+{
+ sigset_t mask;
+
+ sigprocmask(SIG_BLOCK, NULL, &mask);
+ printf("SIGUSR2: %s\n",
+ sigismember(&mask, SIGUSR2) ? "blocked" : "not blocked");
+ printf("SIGTERM: %s\n",
+ sigismember(&mask, SIGTERM) ? "blocked" : "not blocked");
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ } else if (!pid) {
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = handler;
+ act.sa_flags = SA_NODEFER;
+
+ sigaddset(&act.sa_mask, SIGUSR2);
+ sigaddset(&act.sa_mask, SIGTERM);
+
+ sigaction(SIGUSR1, &act, NULL);
+
+ pause();
+ } else {
+ int status;
+
+ sleep(3);
+ kill(pid, SIGUSR1);
+ waitpid(pid, &status, 0);
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/tests/sigint.c b/usr/klibc/tests/sigint.c
new file mode 100644
index 0000000..ec62e33
--- /dev/null
+++ b/usr/klibc/tests/sigint.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+static sig_atomic_t counter = 0;
+
+static void sig_handler(int signum)
+{
+ static const char msg[] = "Signal handler\n";
+
+ (void)signum;
+
+ write(1, msg, sizeof msg - 1);
+ counter++;
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction act, oact;
+ pid_t f;
+ sigset_t set;
+
+ (void)argc;
+
+ memset(&act, 0x00, sizeof(struct sigaction));
+ act.sa_handler = sig_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+
+ /* oact is there for the benefit of strace() */
+ sigaction(SIGINT, &act, &oact);
+ sigaction(SIGTERM, &act, &oact);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+
+ f = fork();
+
+ if (f < 0) {
+ perror(argv[0]);
+ exit(255);
+ } else if (f > 0) {
+ sleep(3);
+ if (counter) {
+ fprintf(stderr, "Signal received while masked!\n");
+ exit(1);
+ }
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+ sleep(3);
+ if (!counter) {
+ fprintf(stderr, "No signal received!\n");
+ exit(1);
+ } else {
+ printf("Signal received OK\n");
+ exit(0);
+ }
+ } else {
+ sleep(1);
+ kill(getppid(), SIGINT);
+ _exit(0);
+ }
+}
diff --git a/usr/klibc/tests/socket.c b/usr/klibc/tests/socket.c
new file mode 100644
index 0000000..48814f9
--- /dev/null
+++ b/usr/klibc/tests/socket.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ret == -1) {
+ fprintf(stderr, "klibc: socket(AF_INET): %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/tests/sscanf.c b/usr/klibc/tests/sscanf.c
new file mode 100644
index 0000000..c06aae4
--- /dev/null
+++ b/usr/klibc/tests/sscanf.c
@@ -0,0 +1,36 @@
+#include <stdio.h>
+
+int main()
+{
+ int ret, err = 0, e1, e2;
+ const char a1[] = "3.0", a2[] = "-12,1000";
+
+ /* int tests */
+ ret = sscanf(a1, "%1d", &e1);
+ if (ret != 1) {
+ printf("Error wrong sscanf int return %d.\n", ret);
+ err++;
+ }
+ if (e1 != 3) {
+ printf("Error wrong sscanf int reading %d.\n", e1);
+ err++;
+ }
+ ret = sscanf(a2, "%3d,%4d", &e1, &e2);
+ if (ret != 2) {
+ printf("Error wrong sscanf int return %d.\n", ret);
+ err++;
+ }
+ if (e1 != -12) {
+ printf("Error wrong sscanf int reading %d.\n", e1);
+ err++;
+ }
+ if (e2 != 1000) {
+ printf("Error wrong sscanf int reading %d.\n", e2);
+ err++;
+ }
+ /* XXX: add more int tests */
+
+ if (err)
+ return err;
+ return 0;
+}
diff --git a/usr/klibc/tests/stat.c b/usr/klibc/tests/stat.c
new file mode 100644
index 0000000..4410833
--- /dev/null
+++ b/usr/klibc/tests/stat.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+static void do_stat(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st)) {
+ perror(path);
+ exit(1);
+ }
+
+ printf("Path = %s\n"
+ " st_dev = %#jx (%u,%u)\n"
+ " st_ino = %ju\n"
+ " st_mode = %#jo\n"
+ " st_nlink = %ju\n"
+ " st_uid = %ju\n"
+ " st_gid = %ju\n"
+ " st_rdev = %#jx (%u,%u)\n"
+ " st_size = %ju\n"
+ " st_blksize = %ju\n"
+ " st_blocks = %ju\n",
+ path,
+ (uintmax_t) st.st_dev, major(st.st_dev), minor(st.st_dev),
+ (uintmax_t) st.st_ino,
+ (uintmax_t) st.st_mode,
+ (uintmax_t) st.st_nlink,
+ (uintmax_t) st.st_uid,
+ (uintmax_t) st.st_gid,
+ (uintmax_t) st.st_rdev, major(st.st_rdev), minor(st.st_rdev),
+ (uintmax_t) st.st_size,
+ (uintmax_t) st.st_blksize, (uintmax_t) st.st_blocks);
+
+#ifdef _STATBUF_ST_NSEC
+ printf(" st_atim = %jd.%09u\n"
+ " st.mtim = %jd.%09u\n"
+ " st.ctim = %jd.%09u\n",
+ (uintmax_t) st.st_atim.tv_sec, (unsigned int)st.st_atim.tv_nsec,
+ (uintmax_t) st.st_mtim.tv_sec, (unsigned int)st.st_mtim.tv_nsec,
+ (uintmax_t) st.st_ctim.tv_sec, (unsigned int)st.st_ctim.tv_nsec);
+#else
+ printf(" st_atime = %jd\n"
+ " st.mtime = %jd\n"
+ " st.ctime = %jd\n",
+ (uintmax_t) st.st_atime,
+ (uintmax_t) st.st_mtime, (uintmax_t) st.st_ctime);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ do_stat(argv[i]);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/statfs.c b/usr/klibc/tests/statfs.c
new file mode 100644
index 0000000..0ac8051
--- /dev/null
+++ b/usr/klibc/tests/statfs.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/vfs.h>
+
+static void do_statfs(const char *path)
+{
+ struct statfs sfs;
+
+ if (statfs(path, &sfs)) {
+ perror(path);
+ exit(1);
+ }
+
+ printf("Path = %s\n"
+ " f_type = %#jx\n"
+ " f_bsize = %jd\n"
+ " f_blocks = %jd\n"
+ " f_bfree = %jd\n"
+ " f_bavail = %jd\n"
+ " f_files = %jd\n"
+ " f_ffree = %jd\n"
+ " f_namelen = %jd\n",
+ path,
+ (uintmax_t) sfs.f_type,
+ (intmax_t) sfs.f_bsize,
+ (intmax_t) sfs.f_blocks,
+ (intmax_t) sfs.f_bfree,
+ (intmax_t) sfs.f_bavail,
+ (intmax_t) sfs.f_files,
+ (intmax_t) sfs.f_ffree, (intmax_t) sfs.f_namelen);
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ do_statfs(argv[i]);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/stdio.c b/usr/klibc/tests/stdio.c
new file mode 100644
index 0000000..895c730
--- /dev/null
+++ b/usr/klibc/tests/stdio.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+
+#define TEST_WORDS (1024*1024)
+
+int main(void)
+{
+ FILE *f;
+ int i, n;
+ uint32_t *buf1, *buf2, *p;
+
+ printf("Hello, World!\nHello again");
+ printf(" - and some more - ");
+ printf("and some more\n");
+
+ buf1 = mmap(NULL, 2*4*TEST_WORDS, PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
+ if (buf1 == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ buf2 = buf1 + TEST_WORDS;
+
+ p = buf1;
+ for (i = 0; i < TEST_WORDS; i++)
+ *p++ = htonl(i);
+
+ f = fopen("test.out", "w+b");
+ if (!f) {
+ perror("fopen");
+ return 1;
+ }
+
+ for (i = 2; i < TEST_WORDS; i += (i >> 1)) {
+ n = fwrite(buf1, 4, i, f);
+ if (n != i) {
+ perror("fwrite");
+ return 1;
+ }
+ }
+
+ fprintf(f, "Writing to the file...\n");
+ fprintf(f, "Writing to the file ");
+ fprintf(f, "some more\n");
+
+ fseek(f, 0, SEEK_SET);
+
+ for (i = 2; i < TEST_WORDS; i += (i >> 1)) {
+ n = fread(buf2, 4, i, f);
+ if (n != i) {
+ perror("fread");
+ return 1;
+ }
+
+ if (memcmp(buf1, buf2, i*4)) {
+ fprintf(stderr, "memory mismatch error, i = %d\n", i);
+ return 1;
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
diff --git a/usr/klibc/tests/strlcpycat.c b/usr/klibc/tests/strlcpycat.c
new file mode 100644
index 0000000..14df0cd
--- /dev/null
+++ b/usr/klibc/tests/strlcpycat.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+ char temp[8];
+ size_t len;
+
+ printf("strlcpy:\n");
+ len = strlcpy(temp, "123", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "123") != 0)
+ goto error;
+
+ len = strlcpy(temp, "", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ len = strlcpy(temp, "1234567890", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "1234567") != 0)
+ goto error;
+
+ len = strlcpy(temp, "123", 1);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ len = strlcpy(temp, "1234567890", 1);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ len = strlcpy(temp, "123", 0);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ len = strlcpy(temp, "1234567890", 0);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ len = strlcpy(temp, "1234567", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "1234567") != 0)
+ goto error;
+
+ len = strlcpy(temp, "12345678", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "1234567") != 0)
+ goto error;
+
+ printf("\n");
+ printf("strlcat:\n");
+ strcpy(temp, "");
+ len = strlcat(temp, "123", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "123") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC") != 0)
+ goto error;
+
+ strcpy(temp, "");
+ len = strlcat(temp, "", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "123", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC123") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "1234567890", sizeof(temp));
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC1234") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "123", 5);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC1") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "123", 1);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC") != 0)
+ goto error;
+
+ strcpy(temp, "ABC");
+ len = strlcat(temp, "123", 0);
+ printf("'%s'len:%zu strlen:%zu\n", temp, len, strlen(temp));
+ if (strcmp(temp, "ABC") != 0)
+ goto error;
+
+ exit(0);
+error:
+ printf("unexpected result\n");
+ exit(1);
+}
diff --git a/usr/klibc/tests/strsearch.c b/usr/klibc/tests/strsearch.c
new file mode 100644
index 0000000..01fd55d
--- /dev/null
+++ b/usr/klibc/tests/strsearch.c
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(void)
+{
+ const char haystack[] = "haystack";
+ const char empty[] = "";
+ const char *p;
+ size_t len;
+
+ p = strchr(haystack, 'a');
+ printf("found 'a' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 1)
+ goto error;
+ p = strchr(haystack, 'b');
+ printf("found 'b' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strchr(haystack, 0);
+ printf("found 0 at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 8)
+ goto error;
+
+ p = strrchr(haystack, 'a');
+ printf("found 'a' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 5)
+ goto error;
+ p = strrchr(haystack, 'b');
+ printf("found 'b' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strrchr(haystack, 0);
+ printf("found 0 at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 8)
+ goto error;
+
+ len = strspn(haystack, "hasty");
+ printf("found %zu chars from 'hasty'\n", len);
+ if (len != 6)
+ goto error;
+ len = strspn(haystack, "haystack");
+ printf("found %zu chars from 'haystack'\n", len);
+ if (len != 8)
+ goto error;
+ len = strspn(haystack, "");
+ printf("found %zu chars from ''\n", len);
+ if (len != 0)
+ goto error;
+
+ len = strcspn(haystack, "stick");
+ printf("found %zu chars not from 'stick'\n", len);
+ if (len != 3)
+ goto error;
+ len = strcspn(haystack, "needle");
+ printf("found %zu chars not from 'needle'\n", len);
+ if (len != 8)
+ goto error;
+ len = strcspn(haystack, "");
+ printf("found %zu chars not from ''\n", len);
+ if (len != 8)
+ goto error;
+
+ p = strpbrk(haystack, "stick");
+ printf("found char from 'stick' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 3)
+ goto error;
+ p = strpbrk(haystack, "needle");
+ printf("found char from 'needle' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strpbrk(haystack, "");
+ printf("found char from '' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+
+ p = strstr(haystack, "stack");
+ printf("found 'stack' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 3)
+ goto error;
+ p = strstr(haystack, "tacks");
+ printf("found 'tacks' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strstr(haystack, "needle");
+ printf("found 'needle' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strstr(haystack, "k");
+ printf("found 'k' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack + 7)
+ goto error;
+ p = strstr(haystack, "b");
+ printf("found 'b' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strstr(haystack, "kk");
+ printf("found 'kk' at offset %zd\n", p ? p - haystack : -1);
+ if (p != NULL)
+ goto error;
+ p = strstr(haystack, "");
+ printf("found '' at offset %zd\n", p ? p - haystack : -1);
+ if (p != haystack)
+ goto error;
+ p = strstr(empty, "");
+ printf("found '' at offset %zd\n", p ? p - empty : -1);
+ if (p != empty)
+ goto error;
+
+ return 0;
+error:
+ printf("unexpected result\n");
+ return 1;
+}
diff --git a/usr/klibc/tests/strtoimax.c b/usr/klibc/tests/strtoimax.c
new file mode 100644
index 0000000..318f2d4
--- /dev/null
+++ b/usr/klibc/tests/strtoimax.c
@@ -0,0 +1,23 @@
+/*
+ * strtoimaxtest.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char *ep;
+ intmax_t iv;
+
+ for (i = 1; i < argc; i++) {
+ iv = strtoimax(argv[i], &ep, 0);
+ printf("strtoimax(\"%s\") = %jd\n", argv[i], iv);
+ if (*ep)
+ printf(" ep = \"%s\"\n", ep);
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/tests/strtotime.c b/usr/klibc/tests/strtotime.c
new file mode 100644
index 0000000..16d2e0f
--- /dev/null
+++ b/usr/klibc/tests/strtotime.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+ struct timeval tv;
+ struct timespec ts;
+ int i;
+ const char *rv, *rs;
+
+ for (i = 1; i < argc; i++) {
+ rs = strtotimespec(argv[i], &ts);
+ rv = strtotimeval(argv[i], &tv);
+ printf("String: \"%s\"\n"
+ "Timespec: %ld.%09ld\n"
+ "Residual: \"%s\"\n"
+ "Timeval: %ld.%06ld\n"
+ "Residual: \"%s\"\n",
+ argv[i],
+ (long)ts.tv_sec, (long)ts.tv_nsec, rs,
+ (long)tv.tv_sec, (long)tv.tv_usec, rv);
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/tests/sysconf.c b/usr/klibc/tests/sysconf.c
new file mode 100644
index 0000000..e32c138
--- /dev/null
+++ b/usr/klibc/tests/sysconf.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+#include <sys/sysconf.h>
+
+int main(void)
+{
+ long rc;
+
+ rc = sysconf(_SC_PAGESIZE);
+ assert(rc > 0);
+ printf("sysconf(_SC_PAGESIZE) = %ld\n", rc);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/testrand48.c b/usr/klibc/tests/testrand48.c
new file mode 100644
index 0000000..26868c7
--- /dev/null
+++ b/usr/klibc/tests/testrand48.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+ unsigned short seed1[] = { 0x1234, 0x5678, 0x9abc };
+ unsigned short *oldseed;
+
+ oldseed = seed48(seed1);
+ printf("Initial seed: %#06x %#06x %#06x\n",
+ oldseed[0], oldseed[1], oldseed[2]);
+
+ printf("lrand48() = %ld\n", lrand48());
+
+ seed48(seed1);
+ printf("mrand48() = %ld\n", mrand48());
+
+ return 1;
+}
diff --git a/usr/klibc/tests/testvsnp.c b/usr/klibc/tests/testvsnp.c
new file mode 100644
index 0000000..7120bda
--- /dev/null
+++ b/usr/klibc/tests/testvsnp.c
@@ -0,0 +1,118 @@
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+int main(void)
+{
+ int r, i;
+ char buffer[512];
+
+ r = snprintf(buffer, 512, "Hello, %d", 37);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'d", 37373737);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'x", 0xdeadbeef);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#X", 0xdeadbeef);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#llo", 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ /* Make sure overflow works correctly */
+ memset(buffer, '\xff', 512);
+ r = snprintf(buffer, 16, "Hello, %'#llo", 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+ for (i = 16; i < 512; i++)
+ assert(buffer[i] == '\xff');
+
+ r = snprintf(buffer, 512, "Hello, %'#40.20llo", 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#-40.20llo", 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#*.*llo", 40, 20,
+ 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#*.*llo", -40, 20,
+ 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#*.*llo", -40, -20,
+ 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %'#*.*llx", -40, -20,
+ 0123456701234567ULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %p", &buffer);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %P", &buffer);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %20p", &buffer);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %-20p", &buffer);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 512, "Hello, %-20p", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 20, "Hello, %'-20p", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 15, "Hello, %'-20p", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 3, "Hello, %'-20p", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ /* This shouldn't change buffer in any way! */
+ r = snprintf(buffer, 0, "Hello, %'-20p", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ for (i = -30; i <= 30; i++) {
+ r = snprintf(buffer, 40, "Hello, %'*p", i, NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer),
+ r);
+ }
+
+ r = snprintf(buffer, 40, "Hello, %'-20s", "String");
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'20s", "String");
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'020s", "String");
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'-20s", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'20s", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'020s", NULL);
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'-20c", '*');
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'20c", '*');
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ r = snprintf(buffer, 40, "Hello, %'020c", '*');
+ printf("buffer = \"%s\" (%d), r = %d\n", buffer, strlen(buffer), r);
+
+ return 0;
+}
diff --git a/usr/klibc/tests/vfork.c b/usr/klibc/tests/vfork.c
new file mode 100644
index 0000000..7adc036
--- /dev/null
+++ b/usr/klibc/tests/vfork.c
@@ -0,0 +1,45 @@
+/*
+ * usr/klibc/tests/vfork.c
+ *
+ * vfork is messy on most architectures. Do our best to test it out.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int main(int argc, char *argv[])
+{
+ pid_t f, rv;
+ int status;
+
+ f = vfork();
+
+ if (f == 0) {
+ printf("Child (%d)...\n", (int)getpid());
+ _exit(123);
+ } else if (f > 0) {
+ int err = 0;
+
+ printf("Parent (child = %d)\n", (int)f);
+
+ rv = waitpid(f, &status, 0);
+ if (rv != f) {
+ printf("waitpid returned %d, errno = %d\n",
+ (int)rv, errno);
+ err++;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 123) {
+ printf("Child process existed with wrong status %d\n",
+ status);
+ err++;
+ }
+ return err;
+ } else {
+ printf("vfork returned %d, errno = %d\n",
+ (int)f, errno);
+ return 127;
+ }
+}
diff --git a/usr/klibc/time.c b/usr/klibc/time.c
new file mode 100644
index 0000000..e812931
--- /dev/null
+++ b/usr/klibc/time.c
@@ -0,0 +1,19 @@
+/*
+ * time.c
+ */
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+time_t time(time_t * t)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ if (t)
+ *t = (time_t) tv.tv_sec;
+
+ return (time_t) tv.tv_sec;
+}
diff --git a/usr/klibc/umount.c b/usr/klibc/umount.c
new file mode 100644
index 0000000..d31a300
--- /dev/null
+++ b/usr/klibc/umount.c
@@ -0,0 +1,12 @@
+/*
+ * umount.c
+ *
+ * Single-argument form of umount
+ */
+
+#include <sys/mount.h>
+
+int umount(const char *dir)
+{
+ return umount2(dir, 0);
+}
diff --git a/usr/klibc/unlink.c b/usr/klibc/unlink.c
new file mode 100644
index 0000000..6dfe66c
--- /dev/null
+++ b/usr/klibc/unlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_unlink
+
+int unlink(const char *pathname)
+{
+ return unlinkat(AT_FDCWD, pathname, 0);
+}
+
+#endif /* __NR_unlink */
diff --git a/usr/klibc/unsetenv.c b/usr/klibc/unsetenv.c
new file mode 100644
index 0000000..c5cc95a
--- /dev/null
+++ b/usr/klibc/unsetenv.c
@@ -0,0 +1,44 @@
+/*
+ * unsetenv.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "env.h"
+
+int unsetenv(const char *name)
+{
+ size_t len;
+ char **p, *q;
+ const char *z;
+
+ if (!name || !name[0]) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ len = 0;
+ for (z = name; *z; z++) {
+ len++;
+ if (*z == '=') {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ if (!environ)
+ return 0;
+
+ for (p = environ; (q = *p); p++) {
+ if (!strncmp(name, q, len) && q[len] == '=')
+ break;
+ }
+
+ for (; (q = *p); p++) {
+ p[0] = p[1];
+ }
+
+ return 0;
+}
diff --git a/usr/klibc/userdb/getgrgid.c b/usr/klibc/userdb/getgrgid.c
new file mode 100644
index 0000000..549aec3
--- /dev/null
+++ b/usr/klibc/userdb/getgrgid.c
@@ -0,0 +1,18 @@
+/*
+ * getgrgid.c
+ *
+ * Dummy getgrgid() to support udev
+ */
+
+#include <grp.h>
+
+#include "userdb.h"
+
+struct group *getgrgid(gid_t gid)
+{
+ if (!gid)
+ return (struct group *)&__root_group;
+
+ errno = ENOENT;
+ return NULL;
+}
diff --git a/usr/klibc/userdb/getgrnam.c b/usr/klibc/userdb/getgrnam.c
new file mode 100644
index 0000000..ac184bc
--- /dev/null
+++ b/usr/klibc/userdb/getgrnam.c
@@ -0,0 +1,18 @@
+/*
+ * getgrnam.c
+ *
+ * Dummy getgrnam() to support udev
+ */
+
+#include <grp.h>
+
+#include "userdb.h"
+
+struct group *getgrnam(const char *name)
+{
+ if (!strcmp(name, "root"))
+ return (struct group *)&__root_group;
+
+ errno = ENOENT;
+ return NULL;
+}
diff --git a/usr/klibc/userdb/getpwnam.c b/usr/klibc/userdb/getpwnam.c
new file mode 100644
index 0000000..3a95688
--- /dev/null
+++ b/usr/klibc/userdb/getpwnam.c
@@ -0,0 +1,19 @@
+/*
+ * getpwnam.c
+ *
+ * Dummy getpwnam() to support udev
+ */
+
+#include <pwd.h>
+
+#include "userdb.h"
+
+
+struct passwd *getpwnam(const char *name)
+{
+ if (!strcmp(name, "root"))
+ return (struct passwd *)&__root_user;
+
+ errno = ENOENT;
+ return NULL;
+}
diff --git a/usr/klibc/userdb/getpwuid.c b/usr/klibc/userdb/getpwuid.c
new file mode 100644
index 0000000..cbe706a
--- /dev/null
+++ b/usr/klibc/userdb/getpwuid.c
@@ -0,0 +1,19 @@
+/*
+ * getpwuid.c
+ *
+ * Dummy getpwuid() to support udev
+ */
+
+#include <pwd.h>
+
+#include "userdb.h"
+
+
+struct passwd *getpwuid(uid_t uid)
+{
+ if (!uid)
+ return (struct passwd *)&__root_user;
+
+ errno = ENOENT;
+ return NULL;
+}
diff --git a/usr/klibc/userdb/root_group.c b/usr/klibc/userdb/root_group.c
new file mode 100644
index 0000000..e936d54
--- /dev/null
+++ b/usr/klibc/userdb/root_group.c
@@ -0,0 +1,12 @@
+/*
+ * root_group.c
+ */
+
+#include "userdb.h"
+
+const struct group __root_group = {
+ .gr_name = "root",
+ .gr_passwd = "",
+ .gr_gid = 0,
+ .gr_mem = NULL
+};
diff --git a/usr/klibc/userdb/root_user.c b/usr/klibc/userdb/root_user.c
new file mode 100644
index 0000000..ee2e99a
--- /dev/null
+++ b/usr/klibc/userdb/root_user.c
@@ -0,0 +1,17 @@
+/*
+ * root_user.c
+ *
+ */
+
+#include "userdb.h"
+#include <paths.h>
+
+const struct passwd __root_user = {
+ .pw_name = "root",
+ .pw_passwd = "",
+ .pw_uid = 0,
+ .pw_gid = 0,
+ .pw_gecos = "root",
+ .pw_dir = "/",
+ .pw_shell = _PATH_BSHELL
+};
diff --git a/usr/klibc/userdb/userdb.h b/usr/klibc/userdb/userdb.h
new file mode 100644
index 0000000..dda093f
--- /dev/null
+++ b/usr/klibc/userdb/userdb.h
@@ -0,0 +1,19 @@
+/*
+ * userdb.h
+ *
+ * Common header file
+ */
+
+#ifndef USERDB_H
+#define USERDB_H
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <errno.h>
+
+extern const struct passwd __root_user;
+extern const struct group __root_group;
+
+#endif /* USERDB_H */
diff --git a/usr/klibc/usleep.c b/usr/klibc/usleep.c
new file mode 100644
index 0000000..67b1533
--- /dev/null
+++ b/usr/klibc/usleep.c
@@ -0,0 +1,17 @@
+/*
+ * usleep.c
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+void usleep(unsigned long usec)
+{
+ struct timespec ts;
+
+ ts.tv_sec = usec / 1000000UL;
+ ts.tv_nsec = (usec % 1000000UL) * 1000;
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ;
+}
diff --git a/usr/klibc/utime.c b/usr/klibc/utime.c
new file mode 100644
index 0000000..bfae2d9
--- /dev/null
+++ b/usr/klibc/utime.c
@@ -0,0 +1,20 @@
+/*
+ * utime.c
+ */
+
+#include <utime.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+int utime(const char *filename, const struct utimbuf *buf)
+{
+ struct timeval tvp[2];
+
+ tvp[0].tv_sec = buf->actime;
+ tvp[0].tv_usec = 0;
+ tvp[1].tv_sec = buf->modtime;
+ tvp[1].tv_usec = 0;
+
+ return utimes(filename, tvp);
+}
diff --git a/usr/klibc/utimes.c b/usr/klibc/utimes.c
new file mode 100644
index 0000000..74cb822
--- /dev/null
+++ b/usr/klibc/utimes.c
@@ -0,0 +1,18 @@
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+int utimes(const char *file, const struct timeval tvp[2])
+{
+ struct timespec ts[2];
+
+ if (tvp) {
+ ts[0].tv_sec = tvp[0].tv_sec;
+ ts[0].tv_nsec = tvp[0].tv_usec * 1000;
+ ts[1].tv_sec = tvp[1].tv_sec;
+ ts[1].tv_nsec = tvp[1].tv_usec * 1000;
+ }
+
+ return utimensat(AT_FDCWD, file, &ts[0], 0);
+}
diff --git a/usr/klibc/vasprintf.c b/usr/klibc/vasprintf.c
new file mode 100644
index 0000000..cdc302f
--- /dev/null
+++ b/usr/klibc/vasprintf.c
@@ -0,0 +1,25 @@
+/*
+ * vasprintf.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int vasprintf(char **bufp, const char *format, va_list ap)
+{
+ va_list ap1;
+ int bytes;
+ char *p;
+
+ va_copy(ap1, ap);
+
+ bytes = vsnprintf(NULL, 0, format, ap1) + 1;
+ va_end(ap1);
+
+ *bufp = p = malloc(bytes);
+ if (!p)
+ return -1;
+
+ return vsnprintf(p, bytes, format, ap);
+}
diff --git a/usr/klibc/version b/usr/klibc/version
new file mode 100644
index 0000000..82bd22f
--- /dev/null
+++ b/usr/klibc/version
@@ -0,0 +1 @@
+2.0.13
diff --git a/usr/klibc/vfork.c b/usr/klibc/vfork.c
new file mode 100644
index 0000000..f2b1a85
--- /dev/null
+++ b/usr/klibc/vfork.c
@@ -0,0 +1,16 @@
+/*
+ * vfork.c
+ *
+ * Emulate vfork() with fork() if necessary
+ */
+
+#include <unistd.h>
+#include <klibc/compiler.h>
+#include <klibc/sysconfig.h>
+
+#if !_KLIBC_NO_MMU && !_KLIBC_REAL_VFORK
+int vfork(void)
+{
+ return fork();
+}
+#endif
diff --git a/usr/klibc/vfprintf.c b/usr/klibc/vfprintf.c
new file mode 100644
index 0000000..6f5663b
--- /dev/null
+++ b/usr/klibc/vfprintf.c
@@ -0,0 +1,26 @@
+/*
+ * vfprintf.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#define BUFFER_SIZE 32768
+
+int vfprintf(FILE * file, const char *format, va_list ap)
+{
+ int rv;
+ char buffer[BUFFER_SIZE];
+
+ rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
+
+ if (rv < 0)
+ return rv;
+
+ if (rv > BUFFER_SIZE - 1)
+ rv = BUFFER_SIZE - 1;
+
+ return _fwrite(buffer, rv, file);
+}
diff --git a/usr/klibc/vprintf.c b/usr/klibc/vprintf.c
new file mode 100644
index 0000000..d6bfeaf
--- /dev/null
+++ b/usr/klibc/vprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vprintf.c
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+int vprintf(const char *format, va_list ap)
+{
+ return vfprintf(stdout, format, ap);
+}
diff --git a/usr/klibc/vsnprintf.c b/usr/klibc/vsnprintf.c
new file mode 100644
index 0000000..26be710
--- /dev/null
+++ b/usr/klibc/vsnprintf.c
@@ -0,0 +1,488 @@
+/*
+ * vsnprintf.c
+ *
+ * vsnprintf(), from which the rest of the printf()
+ * family is built
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+enum flags {
+ FL_ZERO = 0x01, /* Zero modifier */
+ FL_MINUS = 0x02, /* Minus modifier */
+ FL_PLUS = 0x04, /* Plus modifier */
+ FL_TICK = 0x08, /* ' modifier */
+ FL_SPACE = 0x10, /* Space modifier */
+ FL_HASH = 0x20, /* # modifier */
+ FL_SIGNED = 0x40, /* Number is signed */
+ FL_UPPER = 0x80 /* Upper case digits */
+};
+
+/* These may have to be adjusted on certain implementations */
+enum ranks {
+ rank_char = -2,
+ rank_short = -1,
+ rank_int = 0,
+ rank_long = 1,
+ rank_longlong = 2
+};
+
+#define MIN_RANK rank_char
+#define MAX_RANK rank_longlong
+
+#define INTMAX_RANK rank_longlong
+#define SIZE_T_RANK rank_long
+#define PTRDIFF_T_RANK rank_long
+
+#define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
+
+static size_t
+format_int(char *q, size_t n, uintmax_t val, enum flags flags,
+ int base, int width, int prec)
+{
+ char *qq;
+ size_t o = 0, oo;
+ static const char lcdigits[] = "0123456789abcdef";
+ static const char ucdigits[] = "0123456789ABCDEF";
+ const char *digits;
+ uintmax_t tmpval;
+ int minus = 0;
+ int ndigits = 0, nchars;
+ int tickskip, b4tick;
+
+ /* Select type of digits */
+ digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
+
+ /* If signed, separate out the minus */
+ if (flags & FL_SIGNED && (intmax_t) val < 0) {
+ minus = 1;
+ val = (uintmax_t) (-(intmax_t) val);
+ }
+
+ /* Count the number of digits needed. This returns zero for 0. */
+ tmpval = val;
+ while (tmpval) {
+ tmpval /= base;
+ ndigits++;
+ }
+
+ /* Adjust ndigits for size of output */
+
+ if (flags & FL_HASH && base == 8) {
+ if (prec < ndigits + 1)
+ prec = ndigits + 1;
+ }
+
+ if (ndigits < prec) {
+ ndigits = prec; /* Mandatory number padding */
+ } else if (val == 0) {
+ ndigits = 1; /* Zero still requires space */
+ }
+
+ /* For ', figure out what the skip should be */
+ if (flags & FL_TICK) {
+ tickskip = (base == 16) ? 4 : 3;
+ } else {
+ tickskip = ndigits; /* No tick marks */
+ }
+
+ /* Tick marks aren't digits, but generated by the number converter */
+ ndigits += (ndigits - 1) / tickskip;
+
+ /* Now compute the number of nondigits */
+ nchars = ndigits;
+
+ if (minus || (flags & (FL_PLUS | FL_SPACE)))
+ nchars++; /* Need space for sign */
+ if ((flags & FL_HASH) && base == 16) {
+ nchars += 2; /* Add 0x for hex */
+ }
+
+ /* Emit early space padding */
+ if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) {
+ while (width > nchars) {
+ EMIT(' ');
+ width--;
+ }
+ }
+
+ /* Emit nondigits */
+ if (minus)
+ EMIT('-');
+ else if (flags & FL_PLUS)
+ EMIT('+');
+ else if (flags & FL_SPACE)
+ EMIT(' ');
+
+ if ((flags & FL_HASH) && base == 16) {
+ EMIT('0');
+ EMIT((flags & FL_UPPER) ? 'X' : 'x');
+ }
+
+ /* Emit zero padding */
+ if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) {
+ while (width > nchars) {
+ EMIT('0');
+ width--;
+ }
+ }
+
+ /* Generate the number. This is done from right to left. */
+ q += ndigits; /* Advance the pointer to end of number */
+ o += ndigits;
+ qq = q;
+ oo = o; /* Temporary values */
+
+ b4tick = tickskip;
+ while (ndigits > 0) {
+ if (!b4tick--) {
+ qq--;
+ oo--;
+ ndigits--;
+ if (oo < n)
+ *qq = '_';
+ b4tick = tickskip - 1;
+ }
+ qq--;
+ oo--;
+ ndigits--;
+ if (oo < n)
+ *qq = digits[val % base];
+ val /= base;
+ }
+
+ /* Emit late space padding */
+ while ((flags & FL_MINUS) && width > nchars) {
+ EMIT(' ');
+ width--;
+ }
+
+ return o;
+}
+
+int vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ char *q = buffer;
+ size_t o = 0; /* Number of characters output */
+ uintmax_t val = 0;
+ int rank = rank_int; /* Default rank */
+ int width = 0;
+ int prec = -1;
+ int base;
+ size_t sz;
+ enum flags flags = 0;
+ enum {
+ st_normal, /* Ground state */
+ st_flags, /* Special flags */
+ st_width, /* Field width */
+ st_prec, /* Field precision */
+ st_modifiers /* Length or conversion modifiers */
+ } state = st_normal;
+ const char *sarg; /* %s string argument */
+ char carg; /* %c char argument */
+ int slen; /* String length */
+
+ while ((ch = *p++)) {
+ switch (state) {
+ case st_normal:
+ if (ch == '%') {
+ state = st_flags;
+ flags = 0;
+ rank = rank_int;
+ width = 0;
+ prec = -1;
+ } else {
+ EMIT(ch);
+ }
+ break;
+
+ case st_flags:
+ switch (ch) {
+ case '-':
+ flags |= FL_MINUS;
+ break;
+ case '+':
+ flags |= FL_PLUS;
+ break;
+ case '\'':
+ flags |= FL_TICK;
+ break;
+ case ' ':
+ flags |= FL_SPACE;
+ break;
+ case '#':
+ flags |= FL_HASH;
+ break;
+ case '0':
+ flags |= FL_ZERO;
+ break;
+ default:
+ state = st_width;
+ p--; /* Process this character again */
+ break;
+ }
+ break;
+
+ case st_width:
+ if (ch >= '0' && ch <= '9') {
+ width = width * 10 + (ch - '0');
+ } else if (ch == '*') {
+ width = va_arg(ap, int);
+ if (width < 0) {
+ width = -width;
+ flags |= FL_MINUS;
+ }
+ } else if (ch == '.') {
+ prec = 0; /* Precision given */
+ state = st_prec;
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_prec:
+ if (ch >= '0' && ch <= '9') {
+ prec = prec * 10 + (ch - '0');
+ } else if (ch == '*') {
+ prec = va_arg(ap, int);
+ if (prec < 0)
+ prec = -1;
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_modifiers:
+ switch (ch) {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--; /* Shorter rank */
+ break;
+ case 'l':
+ rank++; /* Longer rank */
+ break;
+ case 'j':
+ rank = INTMAX_RANK;
+ break;
+ case 'z':
+ rank = SIZE_T_RANK;
+ break;
+ case 't':
+ rank = PTRDIFF_T_RANK;
+ break;
+ case 'L':
+ case 'q':
+ rank += 2;
+ break;
+ default:
+ /* Output modifiers - terminal sequences */
+
+ /* Next state will be normal */
+ state = st_normal;
+
+ /* Canonicalize rank */
+ if (rank < MIN_RANK)
+ rank = MIN_RANK;
+ else if (rank > MAX_RANK)
+ rank = MAX_RANK;
+
+ switch (ch) {
+ case 'P': /* Upper case pointer */
+ flags |= FL_UPPER;
+ /* fall through */
+ case 'p': /* Pointer */
+ base = 16;
+ prec = (CHAR_BIT*sizeof(void *)+3)/4;
+ flags |= FL_HASH;
+ val = (uintmax_t)(uintptr_t)
+ va_arg(ap, void *);
+ goto is_integer;
+
+ case 'd': /* Signed decimal output */
+ case 'i':
+ base = 10;
+ flags |= FL_SIGNED;
+ switch (rank) {
+ case rank_char:
+ /* Yes, all these casts are
+ needed... */
+ val = (uintmax_t)(intmax_t)
+ (signed char)
+ va_arg(ap, signed int);
+ break;
+ case rank_short:
+ val = (uintmax_t)(intmax_t)
+ (signed short)
+ va_arg(ap, signed int);
+ break;
+ case rank_int:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap, signed int);
+ break;
+ case rank_long:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap, signed long);
+ break;
+ case rank_longlong:
+ val = (uintmax_t)(intmax_t)
+ va_arg(ap,
+ signed long long);
+ break;
+ }
+ goto is_integer;
+ case 'o': /* Octal */
+ base = 8;
+ goto is_unsigned;
+ case 'u': /* Unsigned decimal */
+ base = 10;
+ goto is_unsigned;
+ case 'X': /* Upper case hexadecimal */
+ flags |= FL_UPPER;
+ /* fall through */
+ case 'x': /* Hexadecimal */
+ base = 16;
+ goto is_unsigned;
+
+ is_unsigned:
+ switch (rank) {
+ case rank_char:
+ val = (uintmax_t)
+ (unsigned char)
+ va_arg(ap, unsigned
+ int);
+ break;
+ case rank_short:
+ val = (uintmax_t)
+ (unsigned short)
+ va_arg(ap, unsigned
+ int);
+ break;
+ case rank_int:
+ val = (uintmax_t)
+ va_arg(ap, unsigned
+ int);
+ break;
+ case rank_long:
+ val = (uintmax_t)
+ va_arg(ap, unsigned
+ long);
+ break;
+ case rank_longlong:
+ val = (uintmax_t)
+ va_arg(ap, unsigned
+ long long);
+ break;
+ }
+ /* fall through */
+
+ is_integer:
+ sz = format_int(q, (o < n) ? n - o : 0,
+ val, flags, base,
+ width, prec);
+ q += sz;
+ o += sz;
+ break;
+
+ case 'c': /* Character */
+ carg = (char)va_arg(ap, int);
+ sarg = &carg;
+ slen = 1;
+ goto is_string;
+ case 's': /* String */
+ sarg = va_arg(ap, const char *);
+ sarg = sarg ? sarg : "(null)";
+ slen = strlen(sarg);
+ goto is_string;
+
+ is_string:
+ {
+ char sch;
+ int i;
+
+ if (prec != -1 && slen > prec)
+ slen = prec;
+
+ if (width > slen
+ && !(flags & FL_MINUS)) {
+ char pad =
+ (flags & FL_ZERO) ?
+ '0' : ' ';
+ while (width > slen) {
+ EMIT(pad);
+ width--;
+ }
+ }
+ for (i = slen; i; i--) {
+ sch = *sarg++;
+ EMIT(sch);
+ }
+ if (width > slen
+ && (flags & FL_MINUS)) {
+ while (width > slen) {
+ EMIT(' ');
+ width--;
+ }
+ }
+ }
+ break;
+
+ case 'n':
+ {
+ /* Output the number of
+ characters written */
+
+ switch (rank) {
+ case rank_char:
+ *va_arg(ap,
+ signed char *)
+ = o;
+ break;
+ case rank_short:
+ *va_arg(ap,
+ signed short *)
+ = o;
+ break;
+ case rank_int:
+ *va_arg(ap,
+ signed int *)
+ = o;
+ break;
+ case rank_long:
+ *va_arg(ap,
+ signed long *)
+ = o;
+ break;
+ case rank_longlong:
+ *va_arg(ap,
+ signed long long *)
+ = o;
+ break;
+ }
+ }
+ break;
+
+ default: /* Anything else, including % */
+ EMIT(ch);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Null-terminate the string */
+ if (o < n)
+ *q = '\0'; /* No overflow */
+ else if (n > 0)
+ buffer[n - 1] = '\0'; /* Overflow - terminate at end of buffer */
+
+ return o;
+}
diff --git a/usr/klibc/vsprintf.c b/usr/klibc/vsprintf.c
new file mode 100644
index 0000000..51f5d87
--- /dev/null
+++ b/usr/klibc/vsprintf.c
@@ -0,0 +1,11 @@
+/*
+ * vsprintf.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int vsprintf(char *buffer, const char *format, va_list ap)
+{
+ return vsnprintf(buffer, ~(size_t) 0, format, ap);
+}
diff --git a/usr/klibc/vsscanf.c b/usr/klibc/vsscanf.c
new file mode 100644
index 0000000..b8f068c
--- /dev/null
+++ b/usr/klibc/vsscanf.c
@@ -0,0 +1,392 @@
+/*
+ * vsscanf.c
+ *
+ * vsscanf(), from which the rest of the scanf()
+ * family is built
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifndef LONG_BIT
+#define LONG_BIT (CHAR_BIT*sizeof(long))
+#endif
+
+enum flags {
+ FL_SPLAT = 0x01, /* Drop the value, do not assign */
+ FL_INV = 0x02, /* Character-set with inverse */
+ FL_WIDTH = 0x04, /* Field width specified */
+ FL_MINUS = 0x08, /* Negative number */
+};
+
+enum ranks {
+ rank_char = -2,
+ rank_short = -1,
+ rank_int = 0,
+ rank_long = 1,
+ rank_longlong = 2,
+ rank_ptr = INT_MAX /* Special value used for pointers */
+};
+
+#define MIN_RANK rank_char
+#define MAX_RANK rank_longlong
+
+#define INTMAX_RANK rank_longlong
+#define SIZE_T_RANK rank_long
+#define PTRDIFF_T_RANK rank_long
+
+enum bail {
+ bail_none = 0, /* No error condition */
+ bail_eof, /* Hit EOF */
+ bail_err /* Conversion mismatch */
+};
+
+static inline const char *skipspace(const char *p)
+{
+ while (isspace((unsigned char)*p))
+ p++;
+ return p;
+}
+
+#undef set_bit
+static inline void set_bit(unsigned long *bitmap, unsigned int bit)
+{
+ bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT);
+}
+
+#undef test_bit
+static inline int test_bit(unsigned long *bitmap, unsigned int bit)
+{
+ return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1;
+}
+
+int vsscanf(const char *buffer, const char *format, va_list ap)
+{
+ const char *p = format;
+ char ch;
+ unsigned char uc;
+ const char *q = buffer;
+ const char *qq;
+ uintmax_t val = 0;
+ int rank = rank_int; /* Default rank */
+ unsigned int width = UINT_MAX;
+ int base;
+ enum flags flags = 0;
+ enum {
+ st_normal, /* Ground state */
+ st_flags, /* Special flags */
+ st_width, /* Field width */
+ st_modifiers, /* Length or conversion modifiers */
+ st_match_init, /* Initial state of %[ sequence */
+ st_match, /* Main state of %[ sequence */
+ st_match_range, /* After - in a %[ sequence */
+ } state = st_normal;
+ char *sarg = NULL; /* %s %c or %[ string argument */
+ enum bail bail = bail_none;
+ int converted = 0; /* Successful conversions */
+ unsigned long matchmap[((1 << CHAR_BIT) + (LONG_BIT - 1)) / LONG_BIT];
+ int matchinv = 0; /* Is match map inverted? */
+ unsigned char range_start = 0;
+
+ while ((ch = *p++) && !bail) {
+ switch (state) {
+ case st_normal:
+ if (ch == '%') {
+ state = st_flags;
+ flags = 0;
+ rank = rank_int;
+ width = UINT_MAX;
+ } else if (isspace((unsigned char)ch)) {
+ q = skipspace(q);
+ } else {
+ if (*q == ch)
+ q++;
+ else
+ bail = bail_err; /* Match failure */
+ }
+ break;
+
+ case st_flags:
+ switch (ch) {
+ case '*':
+ flags |= FL_SPLAT;
+ break;
+ case '0'...'9':
+ width = (ch - '0');
+ state = st_width;
+ flags |= FL_WIDTH;
+ break;
+ default:
+ state = st_modifiers;
+ p--; /* Process this character again */
+ break;
+ }
+ break;
+
+ case st_width:
+ if (ch >= '0' && ch <= '9') {
+ width = width * 10 + (ch - '0');
+ } else {
+ state = st_modifiers;
+ p--; /* Process this character again */
+ }
+ break;
+
+ case st_modifiers:
+ switch (ch) {
+ /* Length modifiers - nonterminal sequences */
+ case 'h':
+ rank--; /* Shorter rank */
+ break;
+ case 'l':
+ rank++; /* Longer rank */
+ break;
+ case 'j':
+ rank = INTMAX_RANK;
+ break;
+ case 'z':
+ rank = SIZE_T_RANK;
+ break;
+ case 't':
+ rank = PTRDIFF_T_RANK;
+ break;
+ case 'L':
+ case 'q':
+ rank = rank_longlong; /* long double/long long */
+ break;
+
+ default:
+ /* Output modifiers - terminal sequences */
+ /* Next state will be normal */
+ state = st_normal;
+
+ /* Canonicalize rank */
+ if (rank < MIN_RANK)
+ rank = MIN_RANK;
+ else if (rank > MAX_RANK)
+ rank = MAX_RANK;
+
+ switch (ch) {
+ case 'P': /* Upper case pointer */
+ case 'p': /* Pointer */
+ rank = rank_ptr;
+ base = 0;
+ goto scan_int;
+
+ case 'i': /* Base-independent integer */
+ base = 0;
+ goto scan_int;
+
+ case 'd': /* Decimal integer */
+ base = 10;
+ goto scan_int;
+
+ case 'o': /* Octal integer */
+ base = 8;
+ goto scan_int;
+
+ case 'u': /* Unsigned decimal integer */
+ base = 10;
+ goto scan_int;
+
+ case 'x': /* Hexadecimal integer */
+ case 'X':
+ base = 16;
+ goto scan_int;
+
+ case 'n': /* # of characters consumed */
+ val = (q - buffer);
+ goto set_integer;
+
+ scan_int:
+ q = skipspace(q);
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ val =
+ strntoumax(q, (char **)&qq, base,
+ width);
+ if (qq == q) {
+ bail = bail_err;
+ break;
+ }
+ q = qq;
+ if (!(flags & FL_SPLAT))
+ converted++;
+ /* fall through */
+
+ set_integer:
+ if (!(flags & FL_SPLAT)) {
+ switch (rank) {
+ case rank_char:
+ *va_arg(ap,
+ unsigned char *)
+ = val;
+ break;
+ case rank_short:
+ *va_arg(ap,
+ unsigned short
+ *) = val;
+ break;
+ case rank_int:
+ *va_arg(ap,
+ unsigned int *)
+ = val;
+ break;
+ case rank_long:
+ *va_arg(ap,
+ unsigned long *)
+ = val;
+ break;
+ case rank_longlong:
+ *va_arg(ap,
+ unsigned long
+ long *) = val;
+ break;
+ case rank_ptr:
+ *va_arg(ap, void **) =
+ (void *)
+ (uintptr_t)val;
+ break;
+ }
+ }
+ break;
+
+ case 'c': /* Character */
+ /* Default width == 1 */
+ width = (flags & FL_WIDTH) ? width : 1;
+ if (flags & FL_SPLAT) {
+ while (width--) {
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ }
+ } else {
+ sarg = va_arg(ap, char *);
+ while (width--) {
+ if (!*q) {
+ bail = bail_eof;
+ break;
+ }
+ *sarg++ = *q++;
+ }
+ if (!bail)
+ converted++;
+ }
+ break;
+
+ case 's': /* String */
+ uc = 1; /* Anything nonzero */
+ if (flags & FL_SPLAT) {
+ while (width-- && (uc = *q) &&
+ !isspace(uc)) {
+ q++;
+ }
+ } else {
+ char *sp;
+ sp = sarg = va_arg(ap, char *);
+ while (width-- && (uc = *q) &&
+ !isspace(uc)) {
+ *sp++ = uc;
+ q++;
+ }
+ if (sarg != sp) {
+ /* Terminate output */
+ *sp = '\0';
+ converted++;
+ }
+ }
+ if (!uc)
+ bail = bail_eof;
+ break;
+
+ case '[': /* Character range */
+ sarg = (flags & FL_SPLAT) ? NULL
+ : va_arg(ap, char *);
+ state = st_match_init;
+ matchinv = 0;
+ memset(matchmap, 0, sizeof matchmap);
+ break;
+
+ case '%': /* %% sequence */
+ if (*q == '%')
+ q++;
+ else
+ bail = bail_err;
+ break;
+
+ default: /* Anything else */
+ /* Unknown sequence */
+ bail = bail_err;
+ break;
+ }
+ }
+ break;
+
+ case st_match_init: /* Initial state for %[ match */
+ if (ch == '^' && !(flags & FL_INV)) {
+ matchinv = 1;
+ } else {
+ set_bit(matchmap, (unsigned char)ch);
+ state = st_match;
+ }
+ break;
+
+ case st_match: /* Main state for %[ match */
+ if (ch == ']') {
+ goto match_run;
+ } else if (ch == '-') {
+ range_start = (unsigned char)ch;
+ state = st_match_range;
+ } else {
+ set_bit(matchmap, (unsigned char)ch);
+ }
+ break;
+
+ case st_match_range: /* %[ match after - */
+ if (ch == ']') {
+ /* - was last character */
+ set_bit(matchmap, (unsigned char)'-');
+ goto match_run;
+ } else {
+ int i;
+ for (i = range_start; i < (unsigned char)ch;
+ i++)
+ set_bit(matchmap, i);
+ state = st_match;
+ }
+ break;
+
+ match_run: /* Match expression finished */
+ qq = q;
+ uc = 1; /* Anything nonzero */
+ while (width && (uc = *q)
+ && test_bit(matchmap, uc)^matchinv) {
+ if (sarg)
+ *sarg++ = uc;
+ q++;
+ }
+ if (q != qq && sarg) {
+ *sarg = '\0';
+ converted++;
+ } else {
+ bail = bail_err;
+ }
+ if (!uc)
+ bail = bail_eof;
+ break;
+ }
+ }
+
+ if (bail == bail_eof && !converted)
+ converted = -1; /* Return EOF (-1) */
+
+ return converted;
+}
diff --git a/usr/klibc/wait.c b/usr/klibc/wait.c
new file mode 100644
index 0000000..73bb1a2
--- /dev/null
+++ b/usr/klibc/wait.c
@@ -0,0 +1,12 @@
+/*
+ * wait.c
+ */
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+pid_t wait(int *status)
+{
+ return wait4((pid_t) - 1, status, 0, NULL);
+}
diff --git a/usr/klibc/wait3.c b/usr/klibc/wait3.c
new file mode 100644
index 0000000..1f35414
--- /dev/null
+++ b/usr/klibc/wait3.c
@@ -0,0 +1,12 @@
+/*
+ * wait3.c
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+pid_t wait3(int *status, int options, struct rusage * rusage)
+{
+ return wait4((pid_t) - 1, status, options, rusage);
+}
diff --git a/usr/klibc/waitpid.c b/usr/klibc/waitpid.c
new file mode 100644
index 0000000..a157122
--- /dev/null
+++ b/usr/klibc/waitpid.c
@@ -0,0 +1,12 @@
+/*
+ * waitpid.c
+ */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+ return wait4(pid, status, options, NULL);
+}
diff --git a/usr/klibc/zalloc.c b/usr/klibc/zalloc.c
new file mode 100644
index 0000000..0a5e823
--- /dev/null
+++ b/usr/klibc/zalloc.c
@@ -0,0 +1,17 @@
+/*
+ * zalloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+void *zalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+
+ return ptr;
+}
diff --git a/usr/klibc/zlib/FAQ b/usr/klibc/zlib/FAQ
new file mode 100644
index 0000000..441d910
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/INDEX b/usr/klibc/zlib/INDEX
new file mode 100644
index 0000000..0587e59
--- /dev/null
+++ b/usr/klibc/zlib/INDEX
@@ -0,0 +1,51 @@
+ChangeLog history of changes
+FAQ Frequently Asked Questions about zlib
+INDEX this file
+Makefile makefile for Unix (generated by configure)
+Makefile.in makefile for Unix (template for configure)
+README guess what
+algorithm.txt description of the (de)compression algorithm
+configure configure script for Unix
+zconf.in.h template for zconf.h (used by configure)
+
+amiga/ makefiles for Amiga SAS C
+as400/ makefiles for IBM AS/400
+msdos/ makefiles for MSDOS
+old/ makefiles for various architectures and zlib documentation
+ files that have not yet been updated for zlib 1.2.x
+projects/ projects for various Integrated Development Environments
+qnx/ makefiles for QNX
+win32/ makefiles for Windows
+
+ zlib public header files (must be kept):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzio.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs:
+example.c
+minigzip.c
+
+ unsupported contribution by third parties
+See contrib/README.contrib
diff --git a/usr/klibc/zlib/Kbuild b/usr/klibc/zlib/Kbuild
new file mode 100644
index 0000000..8bff3d5
--- /dev/null
+++ b/usr/klibc/zlib/Kbuild
@@ -0,0 +1,12 @@
+# zlib
+
+klib-y := adler32.o compress.o crc32.o gzio.o
+klib-y += uncompr.o deflate.o trees.o zutil.o
+klib-y += inflate.o infback.o inftrees.o inffast.o
+
+# zlib specific flag
+EXTRA_KLIBCCFLAGS := -DDYNAMIC_CRC_TABLE
+
+# Suppress implicit-fallthrough warning for state machine cases
+# where this is intentional
+EXTRA_KLIBCCFLAGS += $(call cc-disable-warning,implicit-fallthrough)
diff --git a/usr/klibc/zlib/README b/usr/klibc/zlib/README
new file mode 100644
index 0000000..758cc50
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/adler32.c b/usr/klibc/zlib/adler32.c
new file mode 100644
index 0000000..22e1151
--- /dev/null
+++ b/usr/klibc/zlib/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: adler32.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/algorithm.txt b/usr/klibc/zlib/algorithm.txt
new file mode 100644
index 0000000..b022dde
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/compress.c b/usr/klibc/zlib/compress.c
new file mode 100644
index 0000000..4f48f55
--- /dev/null
+++ b/usr/klibc/zlib/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: compress.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/crc32.c b/usr/klibc/zlib/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/crc32.h b/usr/klibc/zlib/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/deflate.c b/usr/klibc/zlib/deflate.c
new file mode 100644
index 0000000..7a9b03d
--- /dev/null
+++ b/usr/klibc/zlib/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: deflate.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/deflate.h b/usr/klibc/zlib/deflate.h
new file mode 100644
index 0000000..0a37d70
--- /dev/null
+++ b/usr/klibc/zlib/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: deflate.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/gzio.c b/usr/klibc/zlib/gzio.c
new file mode 100644
index 0000000..0116ea3
--- /dev/null
+++ b/usr/klibc/zlib/gzio.c
@@ -0,0 +1,1029 @@
+/* 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.
+ */
+
+/* @(#) $Id: gzio.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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;
+ sprintf(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;
+ /* klibc hack */
+ if (errno) 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);
+ /* klibc hack */
+ if (len == 0 && errno) 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 (errno) {
+ 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;
+ /* klibc hack */
+ /* clearerr(s->file); */
+}
diff --git a/usr/klibc/zlib/infback.c b/usr/klibc/zlib/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inffast.c b/usr/klibc/zlib/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inffast.h b/usr/klibc/zlib/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inffixed.h b/usr/klibc/zlib/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inflate.c b/usr/klibc/zlib/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inflate.h b/usr/klibc/zlib/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inftrees.c b/usr/klibc/zlib/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/inftrees.h b/usr/klibc/zlib/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/trees.c b/usr/klibc/zlib/trees.c
new file mode 100644
index 0000000..82578a1
--- /dev/null
+++ b/usr/klibc/zlib/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: trees.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+/* #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/usr/klibc/zlib/trees.h b/usr/klibc/zlib/trees.h
new file mode 100644
index 0000000..aadfa16
--- /dev/null
+++ b/usr/klibc/zlib/trees.h
@@ -0,0 +1,127 @@
+/* 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/usr/klibc/zlib/uncompr.c b/usr/klibc/zlib/uncompr.c
new file mode 100644
index 0000000..debee43
--- /dev/null
+++ b/usr/klibc/zlib/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: uncompr.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/zconf.in.h b/usr/klibc/zlib/zconf.in.h
new file mode 100644
index 0000000..c7575eb
--- /dev/null
+++ b/usr/klibc/zlib/zconf.in.h
@@ -0,0 +1,332 @@
+/* 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
+ */
+
+/* @(#) $Id: zconf.in.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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
+#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/usr/klibc/zlib/zlib.3 b/usr/klibc/zlib/zlib.3
new file mode 100644
index 0000000..90b8162
--- /dev/null
+++ b/usr/klibc/zlib/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/usr/klibc/zlib/zutil.c b/usr/klibc/zlib/zutil.c
new file mode 100644
index 0000000..f9ce953
--- /dev/null
+++ b/usr/klibc/zlib/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: zutil.c,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/klibc/zlib/zutil.h b/usr/klibc/zlib/zutil.h
new file mode 100644
index 0000000..42f52b1
--- /dev/null
+++ b/usr/klibc/zlib/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: zutil.h,v 1.1 2005/02/27 23:15:39 hpa Exp $ */
+
+#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/usr/utils/Kbuild b/usr/utils/Kbuild
new file mode 100644
index 0000000..a389c2a
--- /dev/null
+++ b/usr/utils/Kbuild
@@ -0,0 +1,86 @@
+#
+# Kbuild file for klib utils
+#
+
+progs := chroot dd mkdir mkfifo mknod mount pivot_root umount
+progs += true false sleep ln mv nuke minips cat ls losetup
+progs += insmod uname halt kill readlink cpio sync dmesg
+
+static-y := $(addprefix static/, $(progs))
+shared-y := $(addprefix shared/, $(progs))
+
+# The binary is placed in a subdir, so we need to tell kbuild this
+static/chroot-y := chroot.o
+shared/chroot-y := chroot.o
+static/dd-y := dd.o
+shared/dd-y := dd.o
+static/dmesg-y := dmesg.o
+shared/dmesg-y := dmesg.o
+static/mkdir-y := mkdir.o file_mode.o
+shared/mkdir-y := mkdir.o file_mode.o
+static/mkfifo-y := mkfifo.o file_mode.o
+shared/mkfifo-y := mkfifo.o file_mode.o
+static/mknod-y := mknod.o file_mode.o
+shared/mknod-y := mknod.o file_mode.o
+static/mount-y := mount_main.o mount_opts.o
+shared/mount-y := mount_main.o mount_opts.o
+static/pivot_root-y := pivot_root.o
+shared/pivot_root-y := pivot_root.o
+static/umount-y := umount.o
+shared/umount-y := umount.o
+static/true-y := true.o
+shared/true-y := true.o
+static/false-y := false.o
+shared/false-y := false.o
+static/sleep-y := sleep.o
+shared/sleep-y := sleep.o
+static/ln-y := ln.o
+shared/ln-y := ln.o
+static/ls-y := ls.o
+shared/ls-y := ls.o
+static/mv-y := mv.o
+shared/mv-y := mv.o
+static/nuke-y := nuke.o
+shared/nuke-y := nuke.o
+static/minips-y := minips.o
+shared/minips-y := minips.o
+static/cat-y := cat.o
+shared/cat-y := cat.o
+static/insmod-y := insmod.o
+shared/insmod-y := insmod.o
+static/uname-y := uname.o
+shared/uname-y := uname.o
+static/halt-y := halt.o
+shared/halt-y := halt.o
+static/kill-y := kill.o
+shared/kill-y := kill.o
+static/readlink-y := readlink.o
+shared/readlink-y := readlink.o
+static/cpio-y := cpio.o
+shared/cpio-y := cpio.o
+static/sync-y := sync.o
+shared/sync-y := sync.o
+static/losetup-y := losetup.o
+shared/losetup-y := losetup.o
+
+# Additionally linked targets
+always := static/reboot static/poweroff
+ifdef KLIBCSHAREDFLAGS
+always += shared/reboot shared/poweroff
+endif
+
+$(obj)/static/reboot $(obj)/static/poweroff: $(obj)/static/halt
+ $(call cmd,ln)
+$(obj)/shared/reboot $(obj)/shared/poweroff: $(obj)/shared/halt
+ $(call cmd,ln)
+
+# Clean deletes the static and shared dir
+clean-dirs := static shared
+
+# install the shared binaries by preference
+ifdef KLIBCSHAREDFLAGS
+install-y := $(shared-y)
+else
+install-y := $(static-y)
+endif
+install-link-y := reboot=halt poweroff=halt
diff --git a/usr/utils/cat.c b/usr/utils/cat.c
new file mode 100644
index 0000000..7465148
--- /dev/null
+++ b/usr/utils/cat.c
@@ -0,0 +1,309 @@
+/* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma 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
+ * Kevin Fall.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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 __COPYRIGHT
+#define __COPYRIGHT(arg)
+#endif
+#ifndef __RCSID
+#define __RCSID(arg)
+#endif
+
+#if !defined(lint)
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#if 0
+static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+int rval;
+const char *filename;
+
+int main(int, char *[]);
+void cook_args(char *argv[]);
+void cook_buf(FILE *);
+void raw_args(char *argv[]);
+void raw_cat(int);
+
+int main(int argc, char *argv[])
+{
+ int ch;
+ struct flock stdout_lock;
+
+ while ((ch = getopt(argc, argv, "beflnstuv")) != -1)
+ switch (ch) {
+ case 'b':
+ bflag = nflag = 1; /* -b implies -n */
+ break;
+ case 'e':
+ eflag = vflag = 1; /* -e implies -v */
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = vflag = 1; /* -t implies -v */
+ break;
+ case 'u':
+ /* unimplemented */
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ case '?':
+ (void)fprintf(stderr,
+ "usage: cat [-beflnstuv] [-] [file ...]\n");
+ exit(1);
+ /* NOTREACHED */
+ }
+ argv += optind;
+
+ if (lflag) {
+ stdout_lock.l_len = 0;
+ stdout_lock.l_start = 0;
+ stdout_lock.l_type = F_WRLCK;
+ stdout_lock.l_whence = SEEK_SET;
+ if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1) {
+ perror("fcntl");
+ exit(1);
+ }
+ }
+
+ if (bflag || eflag || nflag || sflag || tflag || vflag)
+ cook_args(argv);
+ else
+ raw_args(argv);
+ if (fclose(stdout)) {
+ perror("fclose");
+ exit(1);
+ }
+ exit(rval);
+ /* NOTREACHED */
+}
+
+void cook_args(char **argv)
+{
+ FILE *fp;
+
+ fp = stdin;
+ filename = "stdin";
+ do {
+ if (*argv) {
+ if (!strcmp(*argv, "-"))
+ fp = stdin;
+ else if ((fp = fopen(*argv,
+ fflag ? "rf" : "r")) == NULL) {
+ perror("fopen");
+ rval = 1;
+ ++argv;
+ continue;
+ }
+ filename = *argv++;
+ }
+ cook_buf(fp);
+ if (fp != stdin)
+ (void)fclose(fp);
+ } while (*argv);
+}
+
+void cook_buf(FILE * fp)
+{
+ int ch, gobble, line, prev;
+ int stdout_err = 0;
+
+ line = gobble = 0;
+ for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
+ if (prev == '\n') {
+ if (ch == '\n') {
+ if (sflag) {
+ if (!gobble && putchar(ch) == EOF)
+ break;
+ gobble = 1;
+ continue;
+ }
+ if (nflag) {
+ if (!bflag) {
+ if (fprintf(stdout,
+ "%6d\t",
+ ++line) < 0) {
+ stdout_err++;
+ break;
+ }
+ } else if (eflag) {
+ if (fprintf(stdout,
+ "%6s\t", "") < 0) {
+ stdout_err++;
+ break;
+ }
+ }
+ }
+ } else if (nflag) {
+ if (fprintf(stdout, "%6d\t", ++line) < 0) {
+ stdout_err++;
+ break;
+ }
+ }
+ }
+ gobble = 0;
+ if (ch == '\n') {
+ if (eflag)
+ if (putchar('$') == EOF)
+ break;
+ } else if (ch == '\t') {
+ if (tflag) {
+ if (putchar('^') == EOF || putchar('I') == EOF)
+ break;
+ continue;
+ }
+ } else if (vflag) {
+ if (!isascii(ch)) {
+ if (putchar('M') == EOF || putchar('-') == EOF)
+ break;
+ ch = (ch) & 0x7f;
+ }
+ if (iscntrl(ch)) {
+ if (putchar('^') == EOF ||
+ putchar(ch == '\177' ? '?' :
+ ch | 0100) == EOF)
+ break;
+ continue;
+ }
+ }
+ if (putchar(ch) == EOF)
+ break;
+ }
+ if (stdout_err) {
+ perror(filename);
+ rval = 1;
+ }
+}
+
+void raw_args(char **argv)
+{
+ int fd;
+
+ fd = fileno(stdin);
+ filename = "stdin";
+ do {
+ if (*argv) {
+ if (!strcmp(*argv, "-"))
+ fd = fileno(stdin);
+ else if (fflag) {
+ struct stat st;
+ fd = open(*argv, O_RDONLY | O_NONBLOCK, 0);
+ if (fd < 0)
+ goto skip;
+
+ if (fstat(fd, &st) == -1) {
+ close(fd);
+ goto skip;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ close(fd);
+ errno = EINVAL;
+ goto skipnomsg;
+ }
+ } else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+ skip:
+ perror(*argv);
+ skipnomsg:
+ rval = 1;
+ ++argv;
+ continue;
+ }
+ filename = *argv++;
+ }
+ raw_cat(fd);
+ if (fd != fileno(stdin))
+ (void)close(fd);
+ } while (*argv);
+}
+
+void raw_cat(int rfd)
+{
+ static char *buf;
+ static char fb_buf[BUFSIZ];
+ static size_t bsize;
+
+ struct stat sbuf;
+ ssize_t nr, nw, off;
+ int wfd;
+
+ wfd = fileno(stdout);
+ if (buf == NULL) {
+ if (fstat(wfd, &sbuf) == 0) {
+ bsize = sbuf.st_blksize > BUFSIZ ?
+ sbuf.st_blksize : BUFSIZ;
+ buf = malloc(bsize);
+ }
+ if (buf == NULL) {
+ buf = fb_buf;
+ bsize = BUFSIZ;
+ }
+ }
+ while ((nr = read(rfd, buf, bsize)) > 0)
+ for (off = 0; nr; nr -= nw, off += nw)
+ if ((nw = write(wfd, buf + off, (size_t) nr)) < 0) {
+ perror("write");
+ exit(1);
+ }
+ if (nr < 0) {
+ fprintf(stderr, "%s: invalid length\n", filename);
+ rval = 1;
+ }
+}
diff --git a/usr/utils/chroot.c b/usr/utils/chroot.c
new file mode 100644
index 0000000..bc1b94f
--- /dev/null
+++ b/usr/utils/chroot.c
@@ -0,0 +1,30 @@
+/*
+ * by rmk
+ */
+#include <unistd.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s newroot command...\n", argv[0]);
+ return 1;
+ }
+
+ if (chroot(argv[1]) == -1) {
+ perror("chroot");
+ return 1;
+ }
+
+ if (chdir("/") == -1) {
+ perror("chdir");
+ return 1;
+ }
+
+ if (execvp(argv[2], argv + 2) == -1) {
+ perror("execvp");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/usr/utils/cpio.c b/usr/utils/cpio.c
new file mode 100644
index 0000000..9b0b6ae
--- /dev/null
+++ b/usr/utils/cpio.c
@@ -0,0 +1,1079 @@
+/* copyin.c - extract or list a cpio archive
+ Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include <fnmatch.h>
+
+# ifndef DIRECTORY_SEPARATOR
+# define DIRECTORY_SEPARATOR '/'
+# endif
+
+# ifndef ISSLASH
+# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
+# endif
+
+/* Return 1 if an array of N objects, each of size S, cannot exist due
+ to size arithmetic overflow. S must be positive and N must be
+ nonnegative. This is a macro, not an inline function, so that it
+ works correctly even when SIZE_MAX < N.
+
+ By gnulib convention, SIZE_MAX represents overflow in size
+ calculations, so the conservative dividend to use here is
+ SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value.
+ However, malloc (SIZE_MAX) fails on all known hosts where
+ sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for
+ exactly-SIZE_MAX allocations on such hosts; this avoids a test and
+ branch when S is known to be 1. */
+# define xalloc_oversized(n, s) \
+ ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n))
+
+#define DISK_IO_BLOCK_SIZE (512)
+
+char *progname = NULL;
+
+/* If true, print a . for each file processed. (-V) */
+char dot_flag = false;
+
+/* Input and output buffers. */
+char *input_buffer, *output_buffer;
+
+/* The size of the input buffer. */
+long input_buffer_size;
+
+/* Current locations in `input_buffer' and `output_buffer'. */
+char *in_buff, *out_buff;
+
+/* Current number of bytes stored at `input_buff' and `output_buff'. */
+long input_size, output_size;
+
+/* Block size value, initially 512. -B sets to 5120. */
+int io_block_size = 512;
+
+struct new_cpio_header {
+ unsigned short c_magic;
+ union {
+ struct {
+ unsigned long c_ino;
+ unsigned long c_mode;
+ unsigned long c_uid;
+ unsigned long c_gid;
+ unsigned long c_nlink;
+ unsigned long c_mtime;
+ unsigned long c_filesize;
+ long c_dev_maj;
+ long c_dev_min;
+ long c_rdev_maj;
+ long c_rdev_min;
+ unsigned long c_namesize;
+ unsigned long c_chksum;
+ };
+ unsigned long c_hdr[13];
+ };
+ char *c_name;
+ char *c_tar_linkname;
+};
+
+/* Total number of bytes read and written for all files.
+ * Now that many tape drives hold more than 4Gb we need more than 32
+ * bits to hold input_bytes and output_bytes.
+ */
+long long input_bytes, output_bytes;
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+static void *xmalloc(size_t n)
+{
+ void *p;
+ if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) {
+ fprintf(stderr, "%s: memory exhausted\n", progname);
+ exit(1);
+ }
+ return p;
+/* return xnmalloc_inline (n, 1); */
+}
+
+/* Clone STRING. */
+
+static char *xstrdup(char const *string)
+{
+ size_t s = strlen(string) + 1;
+ return memcpy(xmalloc(s), string, s);
+/* return xmemdup_inline (string, strlen (string) + 1); */
+}
+
+/* Copy NUM_BYTES of buffer `in_buff' into IN_BUF.
+ `in_buff' may be partly full.
+ When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
+
+static void tape_fill_input_buffer(int in_des, int num_bytes)
+{
+ in_buff = input_buffer;
+ num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
+ input_size = read(in_des, input_buffer, num_bytes);
+ if (input_size < 0) {
+ fprintf(stderr, "%s: read error: %s\n", progname,
+ strerror(errno));
+ exit(1);
+ }
+ if (input_size == 0) {
+ fprintf(stderr, "%s: premature end of file\n", progname);
+ exit(1);
+ }
+ input_bytes += input_size;
+}
+
+/* Write `output_size' bytes of `output_buffer' to file
+ descriptor OUT_DES and reset `output_size' and `out_buff'.
+ If `swapping_halfwords' or `swapping_bytes' is set,
+ do the appropriate swapping first. Our callers have
+ to make sure to only set these flags if `output_size'
+ is appropriate (a multiple of 4 for `swapping_halfwords',
+ 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
+ must always be a multiple of 4 helps us (and our callers)
+ insure this. */
+
+static void disk_empty_output_buffer(int out_des)
+{
+ int bytes_written;
+
+ bytes_written = write(out_des, output_buffer, output_size);
+
+ if (bytes_written != output_size) {
+ fprintf(stderr, "%s: write error: %s\n",
+ progname, strerror(errno));
+ exit(1);
+ }
+ output_bytes += output_size;
+ out_buff = output_buffer;
+ output_size = 0;
+}
+
+/* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full.
+ When `out_buff' fills up, flush it to file descriptor OUT_DES. */
+
+static void disk_buffered_write(char *in_buf, int out_des, long num_bytes)
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Room left in output buffer. */
+
+ while (bytes_left > 0) {
+ space_left = DISK_IO_BLOCK_SIZE - output_size;
+ if (space_left == 0)
+ disk_empty_output_buffer(out_des);
+ else {
+ if (bytes_left < space_left)
+ space_left = bytes_left;
+ memmove(out_buff, in_buf, (unsigned)space_left);
+ out_buff += space_left;
+ output_size += space_left;
+ in_buf += space_left;
+ bytes_left -= space_left;
+ }
+ }
+}
+
+/* Copy a file using the input and output buffers, which may start out
+ partly full. After the copy, the files are not closed nor the last
+ block flushed to output, and the input buffer may still be partly
+ full. If `crc_i_flag' is set, add each byte to `crc'.
+ IN_DES is the file descriptor for input;
+ OUT_DES is the file descriptor for output;
+ NUM_BYTES is the number of bytes to copy. */
+
+static void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes)
+{
+ long size;
+
+ while (num_bytes > 0) {
+ if (input_size == 0)
+ tape_fill_input_buffer(in_des, io_block_size);
+ size = (input_size < num_bytes) ? input_size : num_bytes;
+ disk_buffered_write(in_buff, out_des, size);
+ num_bytes -= size;
+ input_size -= size;
+ in_buff += size;
+ }
+}
+
+/* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+static void tape_buffered_read(char *in_buf, int in_des, long num_bytes)
+{
+ register long bytes_left = num_bytes; /* Bytes needing to be copied. */
+ register long space_left; /* Bytes to copy from input buffer. */
+
+ while (bytes_left > 0) {
+ if (input_size == 0)
+ tape_fill_input_buffer(in_des, io_block_size);
+ if (bytes_left < input_size)
+ space_left = bytes_left;
+ else
+ space_left = input_size;
+ if (in_buf != NULL) {
+ memmove(in_buf, in_buff, (unsigned)space_left);
+ in_buf += space_left;
+ }
+ in_buff += space_left;
+ input_size -= space_left;
+ bytes_left -= space_left;
+ }
+}
+
+/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
+#define tape_toss_input(in_des,num_bytes) \
+(tape_buffered_read(NULL,(in_des),(num_bytes)))
+
+struct deferment {
+ struct deferment *next;
+ struct new_cpio_header header;
+};
+
+static struct deferment *create_deferment(struct new_cpio_header *file_hdr)
+{
+ struct deferment *d;
+ d = (struct deferment *)xmalloc(sizeof(struct deferment));
+ d->header = *file_hdr;
+ d->header.c_name = (char *)xmalloc(strlen(file_hdr->c_name) + 1);
+ strcpy(d->header.c_name, file_hdr->c_name);
+ return d;
+}
+
+static void free_deferment(struct deferment *d)
+{
+ free(d->header.c_name);
+ free(d);
+}
+
+static int link_to_name(char *link_name, char *link_target)
+{
+ int res = link(link_target, link_name);
+ return res;
+}
+
+struct inode_val {
+ unsigned long inode;
+ unsigned long major_num;
+ unsigned long minor_num;
+ char *file_name;
+};
+
+/* Inode hash table. Allocated by first call to add_inode. */
+static struct inode_val **hash_table = NULL;
+
+/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */
+static int hash_size = 22;
+
+/* Number of elements in current hash table. */
+static int hash_num;
+
+/* Do the hash insert. Used in normal inserts and resizing the hash
+ table. It is guaranteed that there is room to insert the item.
+ NEW_VALUE is the pointer to the previously allocated inode, file
+ name association record. */
+
+static void hash_insert(struct inode_val *new_value)
+{
+ int start; /* Home position for the value. */
+ int temp; /* Used for rehashing. */
+
+ /* Hash function is node number modulo the table size. */
+ start = new_value->inode % hash_size;
+
+ /* Do the initial look into the table. */
+ if (hash_table[start] == NULL) {
+ hash_table[start] = new_value;
+ return;
+ }
+
+ /* If we get to here, the home position is full with a different inode
+ record. Do a linear search for the first NULL pointer and insert
+ the new item there. */
+ temp = (start + 1) % hash_size;
+ while (hash_table[temp] != NULL)
+ temp = (temp + 1) % hash_size;
+
+ /* Insert at the NULL. */
+ hash_table[temp] = new_value;
+}
+
+/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
+
+static void
+add_inode(unsigned long node_num, char *file_name, unsigned long major_num,
+ unsigned long minor_num)
+{
+ struct inode_val *temp;
+
+ /* Create new inode record. */
+ temp = (struct inode_val *)xmalloc(sizeof(struct inode_val));
+ temp->inode = node_num;
+ temp->major_num = major_num;
+ temp->minor_num = minor_num;
+ temp->file_name = xstrdup(file_name);
+
+ /* Do we have to increase the size of (or initially allocate)
+ the hash table? */
+ if (hash_num == hash_size || hash_table == NULL) {
+ struct inode_val **old_table; /* Pointer to old table. */
+ int i; /* Index for re-insert loop. */
+
+ /* Save old table. */
+ old_table = hash_table;
+ if (old_table == NULL)
+ hash_num = 0;
+
+ /* Calculate new size of table and allocate it.
+ Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
+ where 3197 and most of the sizes after 6397 are not prime. The other
+ numbers listed are prime. */
+ hash_size = 2 * hash_size + 3;
+ hash_table = (struct inode_val **)
+ xmalloc(hash_size * sizeof(struct inode_val *));
+ memset(hash_table, 0, hash_size * sizeof(struct inode_val *));
+
+ /* Insert the values from the old table into the new table. */
+ for (i = 0; i < hash_num; i++)
+ hash_insert(old_table[i]);
+
+ free(old_table);
+ }
+
+ /* Insert the new record and increment the count of elements in the
+ hash table. */
+ hash_insert(temp);
+ hash_num++;
+}
+
+static char *find_inode_file(unsigned long node_num, unsigned long major_num,
+ unsigned long minor_num)
+{
+ int start; /* Initial hash location. */
+ int temp; /* Rehash search variable. */
+
+ if (hash_table != NULL) {
+ /* Hash function is node number modulo the table size. */
+ start = node_num % hash_size;
+
+ /* Initial look into the table. */
+ if (hash_table[start] == NULL)
+ return NULL;
+ if (hash_table[start]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[start]->file_name;
+
+ /* The home position is full with a different inode record.
+ Do a linear search terminated by a NULL pointer. */
+ for (temp = (start + 1) % hash_size;
+ hash_table[temp] != NULL && temp != start;
+ temp = (temp + 1) % hash_size) {
+ if (hash_table[temp]->inode == node_num
+ && hash_table[start]->major_num == major_num
+ && hash_table[start]->minor_num == minor_num)
+ return hash_table[temp]->file_name;
+ }
+ }
+ return NULL;
+}
+
+/* Try and create a hard link from FILE_NAME to another file
+ with the given major/minor device number and inode. If no other
+ file with the same major/minor/inode numbers is known, add this file
+ to the list of known files and associated major/minor/inode numbers
+ and return -1. If another file with the same major/minor/inode
+ numbers is found, try and create another link to it using
+ link_to_name, and return 0 for success and -1 for failure. */
+
+static int
+link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino)
+{
+ int link_res;
+ char *link_name;
+ link_res = -1;
+ /* Is the file a link to a previously copied file? */
+ link_name = find_inode_file(st_ino, st_dev_maj, st_dev_min);
+ if (link_name == NULL)
+ add_inode(st_ino, file_name, st_dev_maj, st_dev_min);
+ else
+ link_res = link_to_name(file_name, link_name);
+ return link_res;
+}
+
+static void copyin_regular_file(struct new_cpio_header *file_hdr,
+ int in_file_des);
+
+static void warn_junk_bytes(long bytes_skipped)
+{
+ fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n",
+ progname, bytes_skipped);
+}
+
+/* Skip the padding on IN_FILE_DES after a header or file,
+ up to the next header.
+ The number of bytes skipped is based on OFFSET -- the current offset
+ from the last start of a header (or file) -- and the current
+ header type. */
+
+static void tape_skip_padding(int in_file_des, int offset)
+{
+ int pad;
+ pad = (4 - (offset % 4)) % 4;
+
+ if (pad != 0)
+ tape_toss_input(in_file_des, pad);
+}
+
+static int
+try_existing_file(struct new_cpio_header *file_hdr, int in_file_des,
+ int *existing_dir)
+{
+ struct stat file_stat;
+
+ *existing_dir = false;
+ if (lstat(file_hdr->c_name, &file_stat) == 0) {
+ if (S_ISDIR(file_stat.st_mode)
+ && ((file_hdr->c_mode & S_IFMT) == S_IFDIR)) {
+ /* If there is already a directory there that
+ we are trying to create, don't complain about
+ it. */
+ *existing_dir = true;
+ return 0;
+ } else if (S_ISDIR(file_stat.st_mode)
+ ? rmdir(file_hdr->c_name)
+ : unlink(file_hdr->c_name)) {
+ fprintf(stderr, "%s: cannot remove current %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ tape_toss_input(in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ return -1; /* Go to the next file. */
+ }
+ }
+ return 0;
+}
+
+/* The newc and crc formats store multiply linked copies of the same file
+ in the archive only once. The actual data is attached to the last link
+ in the archive, and the other links all have a filesize of 0. When a
+ file in the archive has multiple links and a filesize of 0, its data is
+ probably "attatched" to another file in the archive, so we can't create
+ it right away. We have to "defer" creating it until we have created
+ the file that has the data "attatched" to it. We keep a list of the
+ "defered" links on deferments. */
+
+struct deferment *deferments = NULL;
+
+/* Add a file header to the deferments list. For now they all just
+ go on one list, although we could optimize this if necessary. */
+
+static void defer_copyin(struct new_cpio_header *file_hdr)
+{
+ struct deferment *d;
+ d = create_deferment(file_hdr);
+ d->next = deferments;
+ deferments = d;
+ return;
+}
+
+/* We just created a file that (probably) has some other links to it
+ which have been defered. Go through all of the links on the deferments
+ list and create any which are links to this file. */
+
+static void create_defered_links(struct new_cpio_header *file_hdr)
+{
+ struct deferment *d;
+ struct deferment *d_prev;
+ int ino;
+ int maj;
+ int min;
+ int link_res;
+ ino = file_hdr->c_ino;
+ maj = file_hdr->c_dev_maj;
+ min = file_hdr->c_dev_min;
+ d = deferments;
+ d_prev = NULL;
+ while (d != NULL) {
+ if ((d->header.c_ino == ino) && (d->header.c_dev_maj == maj)
+ && (d->header.c_dev_min == min)) {
+ struct deferment *d_free;
+ link_res =
+ link_to_name(d->header.c_name, file_hdr->c_name);
+ if (link_res < 0) {
+ fprintf(stderr,
+ "%s: cannot link %s to %s: %s\n",
+ progname, d->header.c_name,
+ file_hdr->c_name, strerror(errno));
+ }
+ if (d_prev != NULL)
+ d_prev->next = d->next;
+ else
+ deferments = d->next;
+ d_free = d;
+ d = d->next;
+ free_deferment(d_free);
+ } else {
+ d_prev = d;
+ d = d->next;
+ }
+ }
+}
+
+/* If we had a multiply linked file that really was empty then we would
+ have defered all of its links, since we never found any with data
+ "attached", and they will still be on the deferment list even when
+ we are done reading the whole archive. Write out all of these
+ empty links that are still on the deferments list. */
+
+static void create_final_defers(void)
+{
+ struct deferment *d;
+ int link_res;
+ int out_file_des;
+ struct utimbuf times; /* For setting file times. */
+ /* Initialize this in case it has members we don't know to set. */
+ memset(&times, 0, sizeof(struct utimbuf));
+
+ for (d = deferments; d != NULL; d = d->next) {
+ /* Debian hack: A line, which could cause an endless loop, was
+ removed (97/1/2). It was reported by Ronald F. Guilmette to
+ the upstream maintainers. -BEM */
+ /* Debian hack: This was reported by Horst Knobloch. This bug has
+ been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM
+ */
+ link_res = link_to_maj_min_ino(d->header.c_name,
+ d->header.c_dev_maj,
+ d->header.c_dev_min,
+ d->header.c_ino);
+ if (link_res == 0) {
+ continue;
+ }
+ out_file_des = open(d->header.c_name, O_CREAT | O_WRONLY, 0600);
+ if (out_file_des < 0) {
+ fprintf(stderr, "%s: open %s: %s\n",
+ progname, d->header.c_name, strerror(errno));
+ continue;
+ }
+
+ /* File is now copied; set attributes. */
+ if ((fchown(out_file_des, d->header.c_uid, d->header.c_gid) < 0)
+ && errno != EPERM)
+ fprintf(stderr, "%s: fchown %s: %s\n",
+ progname, d->header.c_name, strerror(errno));
+ /* chown may have turned off some permissions we wanted. */
+ if (fchmod(out_file_des, (int)d->header.c_mode) < 0)
+ fprintf(stderr, "%s: fchmod %s: %s\n",
+ progname, d->header.c_name, strerror(errno));
+
+ if (close(out_file_des) < 0)
+ fprintf(stderr, "%s: close %s: %s\n",
+ progname, d->header.c_name, strerror(errno));
+
+ }
+}
+
+static void
+copyin_regular_file(struct new_cpio_header *file_hdr, int in_file_des)
+{
+ int out_file_des; /* Output file descriptor. */
+
+ /* Can the current file be linked to a previously copied file? */
+ if (file_hdr->c_nlink > 1) {
+ int link_res;
+ if (file_hdr->c_filesize == 0) {
+ /* The newc and crc formats store multiply linked copies
+ of the same file in the archive only once. The
+ actual data is attached to the last link in the
+ archive, and the other links all have a filesize
+ of 0. Since this file has multiple links and a
+ filesize of 0, its data is probably attatched to
+ another file in the archive. Save the link, and
+ process it later when we get the actual data. We
+ can't just create it with length 0 and add the
+ data later, in case the file is readonly. We still
+ lose if its parent directory is readonly (and we aren't
+ running as root), but there's nothing we can do about
+ that. */
+ defer_copyin(file_hdr);
+ tape_toss_input(in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ /* If the file has data (filesize != 0), then presumably
+ any other links have already been defer_copyin'ed(),
+ but GNU cpio version 2.0-2.2 didn't do that, so we
+ still have to check for links here (and also in case
+ the archive was created and later appeneded to). */
+ /* Debian hack: (97/1/2) This was reported by Ronald
+ F. Guilmette to the upstream maintainers. -BEM */
+ link_res = link_to_maj_min_ino(file_hdr->c_name,
+ file_hdr->c_dev_maj,
+ file_hdr->c_dev_min,
+ file_hdr->c_ino);
+ if (link_res == 0) {
+ tape_toss_input(in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ return;
+ }
+ }
+
+ /* If not linked, copy the contents of the file. */
+ out_file_des = open(file_hdr->c_name, O_CREAT | O_WRONLY, 0600);
+
+ if (out_file_des < 0) {
+ fprintf(stderr, "%s: open %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ tape_toss_input(in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ return;
+ }
+
+ copy_files_tape_to_disk(in_file_des, out_file_des,
+ file_hdr->c_filesize);
+ disk_empty_output_buffer(out_file_des);
+
+ if (close(out_file_des) < 0)
+ fprintf(stderr, "%s: close %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+
+ /* File is now copied; set attributes. */
+ if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+ && errno != EPERM)
+ fprintf(stderr, "%s: chown %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0)
+ fprintf(stderr, "%s: chmod %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ if (file_hdr->c_nlink > 1) {
+ /* (see comment above for how the newc and crc formats
+ store multiple links). Now that we have the data
+ for this file, create any other links to it which
+ we defered. */
+ create_defered_links(file_hdr);
+ }
+}
+
+/* In general, we can't use the builtin `basename' function if available,
+ since it has different meanings in different environments.
+ In some environments the builtin `basename' modifies its argument.
+
+ Return the address of the last file name component of NAME. If
+ NAME has no file name components because it is all slashes, return
+ NAME if it is empty, the address of its last slash otherwise. */
+
+static char *base_name(char const *name)
+{
+ char const *base = name;
+ char const *p;
+
+ for (p = base; *p; p++) {
+ if (ISSLASH(*p)) {
+ /* Treat multiple adjacent slashes like a single slash. */
+ do
+ p++;
+ while (ISSLASH(*p));
+
+ /* If the file name ends in slash, use the trailing slash as
+ the basename if no non-slashes have been found. */
+ if (!*p) {
+ if (ISSLASH(*base))
+ base = p - 1;
+ break;
+ }
+
+ /* *P is a non-slash preceded by a slash. */
+ base = p;
+ }
+ }
+
+ return (char *)base;
+}
+
+/* Return the length of of the basename NAME. Typically NAME is the
+ value returned by base_name. Act like strlen (NAME), except omit
+ redundant trailing slashes. */
+
+static size_t base_len(char const *name)
+{
+ size_t len;
+
+ for (len = strlen(name); 1 < len && ISSLASH(name[len - 1]); len--)
+ continue;
+
+ return len;
+}
+
+/* Remove trailing slashes from PATH.
+ Return true if a trailing slash was removed.
+ This is useful when using filename completion from a shell that
+ adds a "/" after directory names (such as tcsh and bash), because
+ the Unix rename and rmdir system calls return an "Invalid argument" error
+ when given a path that ends in "/" (except for the root directory). */
+
+static bool strip_trailing_slashes(char *path)
+{
+ char *base = base_name(path);
+ char *base_lim = base + base_len(base);
+ bool had_slash = (*base_lim != '\0');
+ *base_lim = '\0';
+ return had_slash;
+}
+
+static void copyin_directory(struct new_cpio_header *file_hdr, int existing_dir)
+{
+ int res; /* Result of various function calls. */
+
+ /* Strip any trailing `/'s off the filename; tar puts
+ them on. We might as well do it here in case anybody
+ else does too, since they cause strange things to happen. */
+ strip_trailing_slashes(file_hdr->c_name);
+
+ /* Ignore the current directory. It must already exist,
+ and we don't want to change its permission, ownership
+ or time. */
+ if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') {
+ return;
+ }
+
+ if (!existing_dir)
+ {
+ res = mkdir(file_hdr->c_name, file_hdr->c_mode);
+ } else
+ res = 0;
+ if (res < 0) {
+ /* In some odd cases where the file_hdr->c_name includes `.',
+ the directory may have actually been created by
+ create_all_directories(), so the mkdir will fail
+ because the directory exists. If that's the case,
+ don't complain about it. */
+ struct stat file_stat;
+ if ((errno != EEXIST) ||
+ (lstat(file_hdr->c_name, &file_stat) != 0) ||
+ !(S_ISDIR(file_stat.st_mode))) {
+ fprintf(stderr, "%s: lstat %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ return;
+ }
+ }
+ if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+ && errno != EPERM)
+ fprintf(stderr, "%s: chown %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0)
+ fprintf(stderr, "%s: chmod %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+}
+
+static void copyin_device(struct new_cpio_header *file_hdr)
+{
+ int res; /* Result of various function calls. */
+
+ if (file_hdr->c_nlink > 1) {
+ int link_res;
+ /* Debian hack: This was reported by Horst
+ Knobloch. This bug has been reported to
+ "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */
+ link_res = link_to_maj_min_ino(file_hdr->c_name,
+ file_hdr->c_dev_maj,
+ file_hdr->c_dev_min,
+ file_hdr->c_ino);
+ if (link_res == 0) {
+ return;
+ }
+ }
+
+ res = mknod(file_hdr->c_name, file_hdr->c_mode,
+ makedev(file_hdr->c_rdev_maj, file_hdr->c_rdev_min));
+ if (res < 0) {
+ fprintf(stderr, "%s: mknod %s: %s\n", progname,
+ file_hdr->c_name, strerror(errno));
+ return;
+ }
+ if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+ && errno != EPERM)
+ fprintf(stderr, "%s: chown %s: %s\n", progname,
+ file_hdr->c_name, strerror(errno));
+ /* chown may have turned off some permissions we wanted. */
+ if (chmod(file_hdr->c_name, file_hdr->c_mode) < 0)
+ fprintf(stderr, "%s: chmod %s: %s\n", progname,
+ file_hdr->c_name, strerror(errno));
+}
+
+static void copyin_link(struct new_cpio_header *file_hdr, int in_file_des)
+{
+ char *link_name = NULL; /* Name of hard and symbolic links. */
+ int res; /* Result of various function calls. */
+
+ link_name = (char *)xmalloc(file_hdr->c_filesize + 1);
+ link_name[file_hdr->c_filesize] = '\0';
+ tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+
+ res = symlink(link_name, file_hdr->c_name);
+ if (res < 0) {
+ fprintf(stderr, "%s: symlink %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ free(link_name);
+ return;
+ }
+ if ((lchown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0)
+ && errno != EPERM) {
+ fprintf(stderr, "%s: lchown %s: %s\n",
+ progname, file_hdr->c_name, strerror(errno));
+ }
+ free(link_name);
+}
+
+static void copyin_file(struct new_cpio_header *file_hdr, int in_file_des)
+{
+ int existing_dir;
+
+ if (try_existing_file(file_hdr, in_file_des, &existing_dir) < 0)
+ return;
+
+ /* Do the real copy or link. */
+ switch (file_hdr->c_mode & S_IFMT) {
+ case S_IFREG:
+ copyin_regular_file(file_hdr, in_file_des);
+ break;
+
+ case S_IFDIR:
+ copyin_directory(file_hdr, existing_dir);
+ break;
+
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFSOCK:
+ case S_IFIFO:
+ copyin_device(file_hdr);
+ break;
+
+ case S_IFLNK:
+ copyin_link(file_hdr, in_file_des);
+ break;
+
+ default:
+ fprintf(stderr, "%s: %s: unknown file type\n",
+ progname, file_hdr->c_name);
+ tape_toss_input(in_file_des, file_hdr->c_filesize);
+ tape_skip_padding(in_file_des, file_hdr->c_filesize);
+ }
+}
+
+/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from
+ file descriptor IN_DES, except for the magic number, which is
+ already filled in. */
+
+static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des)
+{
+ char ascii_header[13*8], *ah, hexbuf[9];
+ int i;
+
+ tape_buffered_read(ascii_header, in_des, 13*8);
+ ah = ascii_header;
+ hexbuf[8] = '\0';
+ for (i = 0; i < 13; i++) {
+ memcpy(hexbuf, ah, 8);
+ file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16);
+ ah += 8;
+ }
+
+ /* Sizes > LONG_MAX can currently result in integer overflow
+ in various places. Fail if name is too large. */
+ if (file_hdr->c_namesize > LONG_MAX) {
+ fprintf(stderr, "%s: name size out of range\n",
+ progname);
+ exit(1);
+ }
+
+ /* Read file name from input. */
+ free(file_hdr->c_name);
+ file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize);
+ tape_buffered_read(file_hdr->c_name, in_des,
+ (long)file_hdr->c_namesize);
+
+ /* In SVR4 ASCII format, the amount of space allocated for the header
+ is rounded up to the next long-word, so we might need to drop
+ 1-3 bytes. */
+ tape_skip_padding(in_des, file_hdr->c_namesize + 110);
+
+ /* Fail if file is too large. We could check this earlier
+ but it's helpful to report the name. */
+ if (file_hdr->c_filesize > LONG_MAX) {
+ fprintf(stderr, "%s: %s: file size out of range\n",
+ progname, file_hdr->c_name);
+ exit(1);
+ }
+}
+
+/* Return 16-bit integer I with the bytes swapped. */
+#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff))
+
+/* Read the header, including the name of the file, from file
+ descriptor IN_DES into FILE_HDR. */
+
+static void read_in_header(struct new_cpio_header *file_hdr, int in_des)
+{
+ long bytes_skipped = 0; /* Bytes of junk found before magic number. */
+
+ /* Search for a valid magic number. */
+
+ file_hdr->c_tar_linkname = NULL;
+
+ tape_buffered_read((char *)file_hdr, in_des, 6L);
+ while (1) {
+ if (!strncmp((char *)file_hdr, "070702", 6)
+ || !strncmp((char *)file_hdr, "070701", 6))
+ {
+ if (bytes_skipped > 0)
+ warn_junk_bytes(bytes_skipped);
+
+ read_in_new_ascii(file_hdr, in_des);
+ break;
+ }
+ bytes_skipped++;
+ memmove((char *)file_hdr, (char *)file_hdr + 1, 5);
+ tape_buffered_read((char *)file_hdr + 5, in_des, 1L);
+ }
+}
+
+/* Read the collection from standard input and create files
+ in the file system. */
+
+static void process_copy_in(void)
+{
+ char done = false; /* True if trailer reached. */
+ struct new_cpio_header file_hdr; /* Output header information. */
+ int in_file_des; /* Input file descriptor. */
+
+ /* Initialize the copy in. */
+ file_hdr.c_name = NULL;
+
+ /* only from stdin */
+ in_file_des = 0;
+
+ /* While there is more input in the collection, process the input. */
+ while (!done) {
+ /* Start processing the next file by reading the header. */
+ read_in_header(&file_hdr, in_file_des);
+
+ /* Is this the header for the TRAILER file? */
+ if (strcmp("TRAILER!!!", file_hdr.c_name) == 0) {
+ done = true;
+ break;
+ }
+
+ /* Copy the input file into the directory structure. */
+
+ copyin_file(&file_hdr, in_file_des);
+
+ if (dot_flag)
+ fputc('.', stderr);
+ }
+
+ if (dot_flag)
+ fputc('\n', stderr);
+
+ create_final_defers();
+
+}
+
+/* Initialize the input and output buffers to their proper size and
+ initialize all variables associated with the input and output
+ buffers. */
+
+static void initialize_buffers(void)
+{
+ int in_buf_size, out_buf_size;
+
+ /* Make sure the input buffer can always hold 2 blocks and that it
+ is big enough to hold 1 tar record (512 bytes) even if it
+ is not aligned on a block boundary. The extra buffer space
+ is needed by process_copyin and peek_in_buf to automatically
+ figure out what kind of archive it is reading. */
+ if (io_block_size >= 512)
+ in_buf_size = 2 * io_block_size;
+ else
+ in_buf_size = 1024;
+ out_buf_size = DISK_IO_BLOCK_SIZE;
+
+ input_buffer = (char *)xmalloc(in_buf_size);
+ in_buff = input_buffer;
+ input_buffer_size = in_buf_size;
+ input_size = 0;
+ input_bytes = 0;
+
+ output_buffer = (char *)xmalloc(out_buf_size);
+ out_buff = output_buffer;
+ output_size = 0;
+ output_bytes = 0;
+
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int extract_flag = false;
+
+ progname = argv[0];
+
+ do {
+ c = getopt(argc, argv, "iV");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'V':
+ dot_flag = true;
+ break;
+
+ case 'i':
+ extract_flag = true;
+ break;
+ case '?':
+ fprintf(stderr,
+ "%s: not implemented or invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+
+ }
+ } while (1);
+
+ if (extract_flag) {
+ initialize_buffers();
+
+ process_copy_in();
+ } else {
+ fprintf(stderr, "Usage: %s [-V] -i [< archive]\n", progname);
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/usr/utils/dd.c b/usr/utils/dd.c
new file mode 100644
index 0000000..706b8c3
--- /dev/null
+++ b/usr/utils/dd.c
@@ -0,0 +1,540 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static char *progname;
+
+struct option {
+ const char *opt;
+ char *str;
+ char *arg;
+};
+
+struct conv {
+ const char str[8];
+ unsigned int set;
+ unsigned int exclude;
+};
+
+#define CONV_BLOCK (1<<0)
+#define CONV_UNBLOCK (1<<1)
+
+#define CONV_LCASE (1<<2)
+#define CONV_UCASE (1<<3)
+
+#define CONV_SWAB (1<<4)
+#define CONV_NOERROR (1<<5)
+#define CONV_NOTRUNC (1<<6)
+#define CONV_SYNC (1<<7)
+
+static struct option options[] = {
+ {"bs", NULL, NULL},
+#define OPT_BS (&options[0])
+ {"cbs", NULL, NULL},
+#define OPT_CBS (&options[1])
+ {"conv", NULL, NULL},
+#define OPT_CONV (&options[2])
+ {"count", NULL, NULL},
+#define OPT_COUNT (&options[3])
+ {"ibs", NULL, NULL},
+#define OPT_IBS (&options[4])
+ {"if", NULL, NULL},
+#define OPT_IF (&options[5])
+ {"obs", NULL, NULL},
+#define OPT_OBS (&options[6])
+ {"of", NULL, NULL},
+#define OPT_OF (&options[7])
+ {"seek", NULL, NULL},
+#define OPT_SEEK (&options[8])
+ {"skip", NULL, NULL}
+#define OPT_SKIP (&options[9])
+};
+
+static const struct conv conv_opts[] = {
+ {"block", CONV_BLOCK, CONV_UNBLOCK},
+ {"unblock", CONV_UNBLOCK, CONV_BLOCK},
+ {"lcase", CONV_LCASE, CONV_UCASE},
+ {"ucase", CONV_UCASE, CONV_LCASE},
+ {"swab", CONV_SWAB, 0},
+ {"noerror", CONV_NOERROR, 0},
+ {"notrunc", CONV_NOTRUNC, 0},
+ {"sync", CONV_SYNC, 0},
+};
+
+static size_t cbs;
+static unsigned int conv;
+static unsigned int count;
+static size_t ibs = 512;
+static size_t obs = 512;
+static unsigned int seek;
+static unsigned int skip;
+static char *in_buf;
+static char *out_buf;
+
+static size_t parse_bs(struct option *opt)
+{
+ unsigned long val, realval = 1;
+ char *str = opt->str;
+ int err = 0;
+
+ do {
+ char *s = str;
+ val = strtoul(str, &str, 10);
+ if (s == str || (val == ULONG_MAX && errno == ERANGE)) {
+ err = 1;
+ break;
+ }
+
+ /*
+ * This option may be followed by
+ * 'b', 'k' or 'x'
+ */
+ if (*str == 'b') {
+ val *= 512;
+ str++;
+ } else if (*str == 'k') {
+ val *= 1024;
+ str++;
+ }
+ realval *= val;
+ if (*str != 'x')
+ break;
+ str++;
+ } while (1);
+
+ if (*str != '\0')
+ err = 1;
+
+ if (err) {
+ fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+ exit(1);
+ }
+
+ return (size_t) realval;
+}
+
+static unsigned int parse_num(struct option *opt)
+{
+ unsigned long val;
+ char *str = opt->str;
+
+ val = strtoul(str, &str, 10);
+ if (str == opt->str || (val == ULONG_MAX && errno == ERANGE) ||
+ val > UINT_MAX) {
+ fprintf(stderr, "%s: bad operand `%s'\n", progname, opt->arg);
+ exit(1);
+ }
+
+ return (unsigned int)val;
+}
+
+static int parse_options(int argc, char *argv[])
+{
+ unsigned int i;
+ char *p, *s;
+ int arg;
+
+ /*
+ * We cheat here; we don't parse the operand values
+ * themselves here. We merely split the operands
+ * up. This means that bs=foo bs=1 won't produce
+ * an error.
+ */
+ for (arg = 1; arg < argc; arg++) {
+ unsigned int len;
+
+ s = strchr(argv[arg], '=');
+ if (!s)
+ s = argv[arg]; /* don't recognise this arg */
+
+ len = s - argv[arg];
+ for (i = 0; i < ARRAY_SIZE(options); i++) {
+ if (strncmp(options[i].opt, argv[arg], len) != 0)
+ continue;
+
+ options[i].str = s + 1;
+ options[i].arg = argv[arg];
+ break;
+ }
+
+ if (i == ARRAY_SIZE(options)) {
+ fprintf(stderr, "%s: bad operand `%s'\n",
+ progname, argv[arg]);
+ return 1;
+ }
+ }
+
+ /*
+ * Translate numeric operands.
+ */
+ if (OPT_IBS->str)
+ ibs = parse_bs(OPT_IBS);
+ if (OPT_OBS->str)
+ obs = parse_bs(OPT_OBS);
+ if (OPT_CBS->str)
+ cbs = parse_bs(OPT_CBS);
+ if (OPT_COUNT->str)
+ count = parse_num(OPT_COUNT);
+ if (OPT_SEEK->str)
+ seek = parse_num(OPT_SEEK);
+ if (OPT_SKIP->str)
+ skip = parse_num(OPT_SKIP);
+
+ /*
+ * If bs= is specified, it overrides ibs= and obs=
+ */
+ if (OPT_BS->str)
+ ibs = obs = parse_bs(OPT_BS);
+
+ /*
+ * And finally conv=
+ */
+ if (OPT_CONV->str) {
+ p = OPT_CONV->str;
+
+ while ((s = strsep(&p, ",")) != NULL) {
+ for (i = 0; i < ARRAY_SIZE(conv_opts); i++) {
+ if (strcmp(s, conv_opts[i].str) != 0)
+ continue;
+ conv &= ~conv_opts[i].exclude;
+ conv |= conv_opts[i].set;
+ break;
+ }
+
+ if (i == ARRAY_SIZE(conv_opts)) {
+ fprintf(stderr, "%s: bad conversion `%s'\n",
+ progname, s);
+ return 1;
+ }
+ }
+ }
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK) && cbs == 0) {
+ fprintf(stderr, "%s: block/unblock conversion with zero cbs\n",
+ progname);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int safe_read(int fd, void *buf, size_t size)
+{
+ int ret, count = 0;
+ char *p = buf;
+
+ while (size) {
+ ret = read(fd, p, size);
+
+ /*
+ * If we got EINTR, go again.
+ */
+ if (ret == -1 && errno == EINTR)
+ continue;
+
+ /*
+ * If we encountered an error condition
+ * or read 0 bytes (EOF) return what we
+ * have.
+ */
+ if (ret == -1 || ret == 0)
+ return count ? count : ret;
+
+ /*
+ * We read some bytes.
+ */
+ count += ret;
+ size -= ret;
+ p += ret;
+ }
+
+ return count;
+}
+
+static int skip_blocks(int fd, void *buf, unsigned int blks, size_t size)
+{
+ unsigned int blk;
+ int ret = 0;
+
+ /*
+ * Try to seek.
+ */
+ for (blk = 0; blk < blks; blk++) {
+ ret = lseek(fd, size, SEEK_CUR);
+ if (ret == -1)
+ break;
+ }
+
+ /*
+ * If we failed to seek, read instead.
+ * FIXME: we don't handle short reads here, or
+ * EINTR correctly.
+ */
+ if (blk == 0 && ret == -1 && errno == ESPIPE) {
+ for (blk = 0; blk < blks; blk++) {
+ ret = safe_read(fd, buf, size);
+ if (ret != (int)size)
+ break;
+ }
+ }
+
+ if (ret == -1) {
+ perror("seek/skip");
+ return 1;
+ }
+ return 0;
+}
+
+struct stats {
+ unsigned int in_full;
+ unsigned int in_partial;
+ unsigned int out_full;
+ unsigned int out_partial;
+ unsigned int truncated;
+};
+
+static int do_dd(int rd, int wr, struct stats *stats)
+{
+ unsigned int i;
+ int ret;
+ int fill_val = 0;
+ size_t out_size = 0;
+ size_t in_size;
+ char *buf;
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK))
+ fill_val = ' ';
+
+ while (!OPT_COUNT->str || count-- != 0) {
+ buf = in_buf;
+
+ /*
+ * 1. read ibs-sized buffer
+ */
+ in_size = ret = read(rd, in_buf, ibs);
+ if (ret == -1 || (ret == 0 && (conv & CONV_NOERROR) == 0))
+ break;
+
+ if (in_size == ibs) {
+ stats->in_full++;
+ } else {
+ stats->in_partial++;
+
+ /*
+ * 2. zero (or append spaces)
+ */
+ if (conv & CONV_SYNC) {
+ memset(in_buf + in_size, fill_val,
+ ibs - in_size);
+ in_size = ibs;
+ }
+ }
+
+ /*
+ * 4. swab conversion. With an odd number of bytes,
+ * last byte does not get swapped.
+ */
+ if (conv & CONV_SWAB) {
+ char c;
+
+ for (i = 1; i < in_size; i += 2) {
+ c = in_buf[i - 1];
+ in_buf[i - 1] = in_buf[i];
+ in_buf[i] = c;
+ }
+ }
+
+ /*
+ * 5. remaining conversions.
+ */
+ if (conv & CONV_LCASE)
+ for (i = 0; i < in_size; i++)
+ in_buf[i] = tolower(in_buf[i]);
+
+ if (conv & CONV_UCASE)
+ for (i = 0; i < in_size; i++)
+ in_buf[i] = toupper(in_buf[i]);
+
+ /* block/unblock ? */
+
+ /*
+ * 6. Aggregate into obs sized buffers.
+ * If the in_size is obs-sized and we have no
+ * data waiting, just write "buf" to the output.
+ */
+ if (out_size == 0 && in_size == obs) {
+ write(wr, buf, obs);
+ stats->out_full++;
+ } else {
+ /*
+ * We had data waiting, or we didn't have an
+ * obs-sized input block. We need to append
+ * the input data to the output buffer.
+ */
+ unsigned int space;
+ char *in_ptr = in_buf;
+
+ do {
+ space = obs - out_size;
+ if (space > in_size)
+ space = in_size;
+
+ memcpy(out_buf + out_size, in_ptr, space);
+ out_size += space;
+ in_size -= space;
+ in_ptr += space;
+
+ if (out_size == obs) {
+ write(wr, out_buf, obs);
+ stats->out_full++;
+ out_size = 0;
+ }
+ } while (out_size == 0 && in_size);
+
+ if (in_size) {
+ memcpy(out_buf, in_ptr, in_size);
+ out_size = in_size;
+ }
+ }
+ }
+
+ if (out_size) {
+ write(wr, out_buf, out_size);
+ stats->out_partial++;
+ }
+
+ return 0;
+}
+
+static sigjmp_buf jmp;
+
+static void sigint_handler(int sig)
+{
+ siglongjmp(jmp, -sig);
+}
+
+static int dd(int rd_fd, int wr_fd, struct stats *stats)
+{
+ int ret;
+
+ ret = sigsetjmp(jmp, 1);
+ if (ret == 0) {
+ sysv_signal(SIGINT, sigint_handler);
+ ret = do_dd(rd_fd, wr_fd, stats);
+ }
+
+ sysv_signal(SIGINT, SIG_DFL);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ struct stats stats;
+ int ret;
+ int rd_fd = 0, wr_fd = 1;
+
+ progname = argv[0];
+
+ ret = parse_options(argc, argv);
+ if (ret)
+ return ret;
+
+ if (conv & (CONV_BLOCK | CONV_UNBLOCK)) {
+ fprintf(stderr, "%s: block/unblock not implemented\n",
+ progname);
+ return 1;
+ }
+
+ in_buf = malloc(ibs);
+ if (!in_buf) {
+ perror("malloc ibs");
+ return 1;
+ }
+
+ out_buf = malloc(obs);
+ if (!out_buf) {
+ perror("malloc obs");
+ return 1;
+ }
+
+ /*
+ * Open the input file, if specified.
+ */
+ if (OPT_IF->str) {
+ rd_fd = open(OPT_IF->str, O_RDONLY);
+ if (rd_fd == -1) {
+ perror("open input file");
+ return 1;
+ }
+ }
+
+ /*
+ * Open the output file, if specified.
+ */
+ if (OPT_OF->str) {
+ int flags = O_WRONLY|O_CREAT;
+ flags |= (conv & CONV_NOTRUNC) ? 0 : O_TRUNC;
+ wr_fd = open(OPT_OF->str, flags, 0666);
+ if (wr_fd == -1) {
+ perror("open output file");
+ close(rd_fd);
+ return 1;
+ }
+ }
+
+ /*
+ * Skip obs-sized blocks of output file.
+ */
+ if (OPT_SEEK->str && skip_blocks(wr_fd, out_buf, seek, obs)) {
+ close(rd_fd);
+ close(wr_fd);
+ return 1;
+ }
+
+ /*
+ * Skip ibs-sized blocks of input file.
+ */
+ if (OPT_SKIP->str && skip_blocks(rd_fd, in_buf, skip, ibs)) {
+ close(rd_fd);
+ close(wr_fd);
+ return 1;
+ }
+
+ memset(&stats, 0, sizeof(stats));
+
+ /*
+ * Do the real work
+ */
+ ret = dd(rd_fd, wr_fd, &stats);
+
+ if (close(rd_fd) == -1)
+ perror(OPT_IF->str ? OPT_IF->str : "stdin");
+ if (close(wr_fd) == -1)
+ perror(OPT_OF->str ? OPT_OF->str : "stdout");
+
+ fprintf(stderr, "%u+%u records in\n", stats.in_full, stats.in_partial);
+ fprintf(stderr, "%u+%u records out\n",
+ stats.out_full, stats.out_partial);
+ if (stats.truncated)
+ fprintf(stderr, "%u truncated record%s\n",
+ stats.truncated, stats.truncated == 1 ? "" : "s");
+
+ /*
+ * ret will be -SIGINT if we got a SIGINT. Raise
+ * the signal again to cause us to terminate with
+ * SIGINT status.
+ */
+ if (ret == -SIGINT)
+ raise(SIGINT);
+
+ return ret;
+}
diff --git a/usr/utils/dmesg.c b/usr/utils/dmesg.c
new file mode 100644
index 0000000..1960713
--- /dev/null
+++ b/usr/utils/dmesg.c
@@ -0,0 +1,79 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/klog.h>
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage: %s [-c]\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+ char *buf = NULL;
+ const char *p;
+ int c;
+ int bufsz = 0;
+ int cmd = 3; /* Read all messages remaining in the ring buffer */
+ int len = 0;
+ int opt;
+ int newline;
+
+ while ((opt = getopt(argc, argv, "c")) != -1) {
+ switch (opt) {
+ /* Read and clear all messages remaining in the ring buffer */
+ case 'c':
+ cmd = 4;
+ break;
+ case '?':
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (!bufsz) {
+ len = klogctl(10, NULL, 0); /* Get size of log buffer */
+ if (len > 0)
+ bufsz = len;
+ }
+
+ if (bufsz) {
+ int sz = bufsz + 8;
+
+ buf = (char *)malloc(sz);
+ len = klogctl(cmd, buf, sz);
+ }
+
+ if (len < 0) {
+ perror("klogctl");
+ exit(1);
+ }
+
+ newline = 1;
+ p = buf;
+ while ((c = *p)) {
+ switch (c) {
+ case '\n':
+ newline = 1;
+ putchar(c);
+ p++;
+ break;
+ case '<':
+ if (newline && isdigit(p[1]) && p[2] == '>') {
+ p += 3;
+ break;
+ }
+ /* else fall through */
+ default:
+ newline = 0;
+ putchar(c);
+ p++;
+ }
+ }
+ if (!newline)
+ putchar('\n');
+
+ return 0;
+}
diff --git a/usr/utils/false.c b/usr/utils/false.c
new file mode 100644
index 0000000..2c3243a
--- /dev/null
+++ b/usr/utils/false.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 1;
+}
diff --git a/usr/utils/file_mode.c b/usr/utils/file_mode.c
new file mode 100644
index 0000000..48f7f43
--- /dev/null
+++ b/usr/utils/file_mode.c
@@ -0,0 +1,143 @@
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "file_mode.h"
+
+extern char *progname;
+
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask)
+{
+ char *clause;
+
+ if (isdigit(*arg) && *arg < '8') {
+ unsigned long num;
+
+ num = strtoul(arg, NULL, 8);
+ if ((num == ULONG_MAX && errno == ERANGE) || num > 07777) {
+ fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+ arg);
+ exit(255);
+ }
+ return (mode_t) num;
+ }
+
+ while ((clause = strsep(&arg, ",")) != NULL) {
+ mode_t who = 0;
+ int action;
+ char *p = clause;
+
+ /*
+ * Parse the who list. Optional.
+ */
+ while (1) {
+ switch (*p++) {
+ case 'u':
+ who |= S_IRWXU | S_ISUID;
+ continue;
+ case 'g':
+ who |= S_IRWXG | S_ISGID;
+ continue;
+ case 'o':
+ who |= S_IRWXO | S_ISVTX;
+ continue;
+ case 'a':
+ who =
+ S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID |
+ S_ISGID | S_ISVTX;
+ continue;
+ }
+ /* undo the increment above */
+ p--;
+ break;
+ }
+
+ if (who == 0)
+ who = (~sumask) | S_ISVTX;
+
+ /*
+ * Parse an action list. Must be at least one action.
+ */
+ while (*p) {
+ mode_t perm = 0;
+
+ /*
+ * Parse the action
+ */
+ action = *p;
+ if (action == '+' || action == '-' || action == '=')
+ p++;
+
+ /*
+ * Parse perm
+ */
+ while (*p) {
+ switch (*p++) {
+ case 'r':
+ perm |= S_IRUSR | S_IRGRP | S_IROTH;
+ continue;
+ case 'w':
+ perm |= S_IWUSR | S_IWGRP | S_IWOTH;
+ continue;
+ case 'x':
+ perm |= S_IXUSR | S_IXGRP | S_IXOTH;
+ continue;
+ case 'X':
+ perm |= S_ISVTX;
+ continue;
+ case 's':
+ perm |= S_ISUID | S_ISGID;
+ continue;
+ case 'u':
+ perm = mode & S_IRWXU;
+ perm |= perm >> 3 | perm >> 6;
+ if (mode & S_ISUID)
+ perm |= S_ISGID;
+ continue;
+ case 'g':
+ perm = mode & S_IRWXG;
+ perm |= perm << 3 | perm >> 3;
+ if (mode & S_ISGID)
+ perm |= S_ISUID;
+ continue;
+ case 'o':
+ perm = mode & S_IRWXO;
+ perm |= perm << 6 | perm << 3;
+ continue;
+ }
+ /* undo the increment above */
+ p--;
+ break;
+ }
+
+ perm &= who;
+
+ switch (action) {
+ case '+':
+ mode |= perm;
+ continue;
+
+ case '-':
+ mode &= ~perm;
+ continue;
+
+ case '=':
+ mode &= ~who;
+ mode |= perm;
+ continue;
+ }
+
+ if (!action)
+ break;
+ fprintf(stderr, "%s: invalid mode `%s'\n", progname,
+ clause);
+ exit(255);
+ }
+ }
+
+ return mode;
+}
diff --git a/usr/utils/file_mode.h b/usr/utils/file_mode.h
new file mode 100644
index 0000000..364f603
--- /dev/null
+++ b/usr/utils/file_mode.h
@@ -0,0 +1,6 @@
+#ifndef UTILS_FILE_MODE_H
+#define UTILS_FILE_MODE_H
+
+mode_t parse_file_mode(char *arg, mode_t mode, mode_t sumask);
+
+#endif /* UTILS_FILE_MODE_H */
diff --git a/usr/utils/halt.c b/usr/utils/halt.c
new file mode 100644
index 0000000..368f095
--- /dev/null
+++ b/usr/utils/halt.c
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/reboot.h>
+#include <klibc/compiler.h>
+
+static __noreturn usage(void)
+{
+ static char mesg[] = "Usage: {halt|reboot|poweroff} [-n] [reboot-arg]\n";
+ write(2, mesg, sizeof(mesg) - 1);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int cmd = 0; /* initalize to shut gcc up */
+ int do_sync = 1;
+ char *ptr, *ptr2;
+ char *reboot_arg = NULL;
+
+ /* Which action (program name)? */
+ ptr2 = ptr = argv[0];
+ while (*ptr2)
+ if (*ptr2++ == '/')
+ ptr = ptr2;
+ if (*ptr == 'r')
+ cmd = LINUX_REBOOT_CMD_RESTART;
+ else if (*ptr == 'h')
+ cmd = LINUX_REBOOT_CMD_HALT;
+ else if (*ptr == 'p')
+ cmd = LINUX_REBOOT_CMD_POWER_OFF;
+ else
+ usage();
+
+ /* Walk options */
+ while (*++argv)
+ if (**argv == '-') {
+ switch (*++*argv) {
+ case 'f':
+ break; /* -f assumed */
+ case 'n':
+ do_sync = 0;
+ break;
+ default:
+ usage();
+ }
+ } else if (cmd == LINUX_REBOOT_CMD_RESTART) {
+ reboot_arg = *argv;
+ cmd = LINUX_REBOOT_CMD_RESTART2;
+ } else {
+ usage(); /* args, not reboot == error */
+ }
+
+ if (do_sync)
+ sync();
+ reboot(LINUX_REBOOT_CMD_CAD_OFF, NULL); /* Enable CTRL+ALT+DEL */
+ if (!reboot(cmd, reboot_arg)) {
+ /* Success. Currently, CMD_HALT returns, so stop the world */
+ /* kill(-1, SIGSTOP); */
+ kill(getpid(), SIGSTOP);
+ }
+ write(2, "failed.\n", 8);
+ return 1;
+}
diff --git a/usr/utils/insmod.c b/usr/utils/insmod.c
new file mode 100644
index 0000000..47b5880
--- /dev/null
+++ b/usr/utils/insmod.c
@@ -0,0 +1,140 @@
+/* insmod.c: insert a module into the kernel.
+ Copyright (C) 2001 Rusty Russell.
+ Copyright (C) 2002 Rusty Russell, IBM Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/* This really needs to be in a header file... */
+extern long init_module(void *, unsigned long, const char *);
+
+static void print_usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s filename [args]\n", progname);
+ exit(1);
+}
+
+/* We use error numbers in a loose translation... */
+static const char *moderror(int err)
+{
+ switch (err) {
+ case ENOEXEC:
+ return "Invalid module format";
+ case ENOENT:
+ return "Unknown symbol in module";
+ case ESRCH:
+ return "Module has wrong symbol version";
+ case EINVAL:
+ return "Invalid parameters";
+ default:
+ return strerror(err);
+ }
+}
+
+static void *grab_file(const char *filename, unsigned long *size)
+{
+ unsigned int max = 16384;
+ int ret, fd;
+ void *buffer = malloc(max);
+
+ if (streq(filename, "-"))
+ fd = dup(STDIN_FILENO);
+ else
+ fd = open(filename, O_RDONLY, 0);
+
+ if (fd < 0)
+ return NULL;
+
+ *size = 0;
+ while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
+ *size += ret;
+ if (*size == max)
+ buffer = realloc(buffer, max *= 2);
+ }
+ if (ret < 0) {
+ free(buffer);
+ buffer = NULL;
+ }
+ close(fd);
+ return buffer;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ long int ret;
+ unsigned long len;
+ void *file;
+ char *filename, *options = strdup("");
+ char *progname = argv[0];
+
+ if (argv[1] && (streq(argv[1], "--version") || streq(argv[1], "-V"))) {
+ puts("klibc insmod");
+ exit(0);
+ }
+
+ /* Ignore old options, for backwards compat. */
+ while (argv[1] && (streq(argv[1], "-p")
+ || streq(argv[1], "-s")
+ || streq(argv[1], "-f"))) {
+ argv++;
+ argc--;
+ }
+
+ filename = argv[1];
+ if (!filename)
+ print_usage(progname);
+
+ /* Rest is options */
+ for (i = 2; i < argc; i++) {
+ options = realloc(options,
+ strlen(options) + 2 + strlen(argv[i]) + 2);
+ /* Spaces handled by "" pairs, but no way of escaping
+ quotes */
+ if (strchr(argv[i], ' '))
+ strcat(options, "\"");
+ strcat(options, argv[i]);
+ if (strchr(argv[i], ' '))
+ strcat(options, "\"");
+ strcat(options, " ");
+ }
+
+ file = grab_file(filename, &len);
+ if (!file) {
+ fprintf(stderr, "insmod: can't read '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ ret = init_module(file, len, options);
+ if (ret != 0) {
+ fprintf(stderr, "insmod: error inserting '%s': %li %s\n",
+ filename, ret, moderror(errno));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/usr/utils/kill.c b/usr/utils/kill.c
new file mode 100644
index 0000000..188f1b5
--- /dev/null
+++ b/usr/utils/kill.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s pid\n", progname);
+ exit(1);
+}
+int main(int argc, char *argv[])
+{
+ long pid;
+ char *endp;
+
+ progname = argv[0];
+ if (argc != 2)
+ usage();
+
+ pid = strtol(argv[1], &endp, 10);
+ if (*endp != '\0') {
+ perror("pid");
+ usage();
+ }
+
+ if (kill(pid, SIGTERM) == -1) {
+ perror("kill");
+ exit(-1);
+ }
+ exit(0);
+}
diff --git a/usr/utils/ln.c b/usr/utils/ln.c
new file mode 100644
index 0000000..e826eb8
--- /dev/null
+++ b/usr/utils/ln.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/limits.h>
+
+int main(int argc, char *argv[])
+{
+ int c, s, f;
+ char *p;
+ struct stat sb;
+
+ s = f = 0;
+ do {
+ c = getopt(argc, argv, "sf");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+
+ case 's':
+ s = 1;
+ break;
+ case 'f':
+ f = 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ return 1;
+ }
+
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-s] [-f] target link\n", argv[0]);
+ return 1;
+ }
+
+ memset(&sb, 0, sizeof(struct stat));
+ if (stat(argv[argc - 1], &sb) < 0 && argc - optind > 2) {
+ if (!(S_ISDIR(sb.st_mode))) {
+ fprintf(stderr,
+ "multiple targets and %s is not a directory\n",
+ argv[argc - 1]);
+ return 1;
+ }
+ }
+
+ for (c = optind; c < argc - 1; c++) {
+ char target[PATH_MAX];
+
+ p = strrchr(argv[c], '/');
+ p++;
+
+ if (S_ISDIR(sb.st_mode))
+ snprintf(target, PATH_MAX, "%s/%s", argv[argc - 1], p);
+ else
+ snprintf(target, PATH_MAX, "%s", argv[argc - 1]);
+
+ if (f)
+ unlink(target);
+
+ if (s) {
+ if (symlink(argv[c], target) == -1)
+ perror(target);
+ } else {
+ if (link(argv[c], target) == -1)
+ perror(target);
+ }
+ }
+
+ return 0;
+}
diff --git a/usr/utils/losetup.c b/usr/utils/losetup.c
new file mode 100644
index 0000000..16159eb
--- /dev/null
+++ b/usr/utils/losetup.c
@@ -0,0 +1,400 @@
+/* Originally from Ted's losetup.c */
+
+#define LOOPMAJOR 7
+
+/*
+ * losetup.c - setup and control loop devices
+ */
+
+/* We want __u64 to be unsigned long long */
+#define __SANE_USERSPACE_TYPES__
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/sysmacros.h>
+#include <stdarg.h>
+#include <linux/loop.h>
+
+extern int verbose;
+extern char *progname;
+extern char *xstrdup (const char *s); /* not: #include "sundries.h" */
+extern void error (const char *fmt, ...); /* idem */
+
+/* caller guarantees n > 0 */
+void xstrncpy(char *dest, const char *src, size_t n)
+{
+ strncpy(dest, src, n-1);
+ dest[n-1] = 0;
+}
+
+
+static int show_loop(char *device)
+{
+ struct loop_info64 loopinfo64;
+ int fd, errsv;
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ int errsv = errno;
+ fprintf(stderr, "loop: can't open device %s: %s\n",
+ device, strerror (errsv));
+ return 2;
+ }
+
+ if (ioctl(fd, LOOP_GET_STATUS64, &loopinfo64) == 0) {
+
+ loopinfo64.lo_file_name[LO_NAME_SIZE-2] = '*';
+ loopinfo64.lo_file_name[LO_NAME_SIZE-1] = 0;
+ loopinfo64.lo_crypt_name[LO_NAME_SIZE-1] = 0;
+
+ printf("%s: [%04llx]:%llu (%s)",
+ device, loopinfo64.lo_device, loopinfo64.lo_inode,
+ loopinfo64.lo_file_name);
+
+ if (loopinfo64.lo_offset)
+ printf(", offset %lld", loopinfo64.lo_offset);
+
+ if (loopinfo64.lo_sizelimit)
+ printf(", sizelimit %lld", loopinfo64.lo_sizelimit);
+
+ if (loopinfo64.lo_encrypt_type ||
+ loopinfo64.lo_crypt_name[0]) {
+ const char *e = (const char *)loopinfo64.lo_crypt_name;
+
+ if (*e == 0 && loopinfo64.lo_encrypt_type == 1)
+ e = "XOR";
+ printf(", encryption %s (type %d)",
+ e, loopinfo64.lo_encrypt_type);
+ }
+ printf("\n");
+ close (fd);
+ return 0;
+ }
+
+ errsv = errno;
+ fprintf(stderr, "loop: can't get info on device %s: %s\n",
+ device, strerror (errsv));
+ close (fd);
+ return 1;
+}
+
+int
+is_loop_device (const char *device) {
+ struct stat statbuf;
+
+ return (stat(device, &statbuf) == 0 &&
+ S_ISBLK(statbuf.st_mode) &&
+ major(statbuf.st_rdev) == LOOPMAJOR);
+}
+
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+char * find_unused_loop_device (void)
+{
+ char dev[20];
+ int fd, rc;
+
+ fd = open("/dev/loop-control", O_RDWR);
+ if (fd < 0) {
+ error("%s: could not open /dev/loop-control. Maybe this kernel "
+ "does not know\n"
+ " about the loop device? (If so, recompile or "
+ "`modprobe loop'.)", progname);
+ return NULL;
+ }
+ rc = ioctl(fd, LOOP_CTL_GET_FREE, 0);
+ close(fd);
+ if (rc < 0) {
+ error("%s: could not find any free loop device", progname);
+ return NULL;
+ }
+
+ sprintf(dev, "/dev/loop%d", rc);
+ return xstrdup(dev);
+}
+
+/*
+ * A function to read the passphrase either from the terminal or from
+ * an open file descriptor.
+ */
+static char * xgetpass(int pfd, const char *prompt)
+{
+ char *pass;
+ int buflen, i;
+
+ pass = NULL;
+ buflen = 0;
+ for (i=0; ; i++) {
+ if (i >= buflen-1) {
+ /* we're running out of space in the buffer.
+ * Make it bigger: */
+ char *tmppass = pass;
+ buflen += 128;
+ pass = realloc(tmppass, buflen);
+ if (pass == NULL) {
+ /* realloc failed. Stop reading. */
+ error("Out of memory while reading passphrase");
+ pass = tmppass; /* the old buffer hasn't changed */
+ break;
+ }
+ }
+ if (read(pfd, pass+i, 1) != 1 ||
+ pass[i] == '\n' || pass[i] == 0)
+ break;
+ }
+
+ if (pass == NULL)
+ return "";
+
+ pass[i] = 0;
+ return pass;
+}
+
+static int digits_only(const char *s)
+{
+ while (*s)
+ if (!isdigit(*s++))
+ return 0;
+ return 1;
+}
+
+int set_loop(const char *device, const char *file, unsigned long long offset,
+ const char *encryption, int pfd, int *loopro) {
+ struct loop_info64 loopinfo64;
+ int fd, ffd, mode, i;
+ char *pass;
+
+ mode = (*loopro ? O_RDONLY : O_RDWR);
+ if ((ffd = open(file, mode)) < 0) {
+ if (!*loopro && errno == EROFS)
+ ffd = open(file, mode = O_RDONLY);
+ if (ffd < 0) {
+ perror(file);
+ return 1;
+ }
+ }
+ if ((fd = open(device, mode)) < 0) {
+ perror (device);
+ return 1;
+ }
+ *loopro = (mode == O_RDONLY);
+
+ memset(&loopinfo64, 0, sizeof(loopinfo64));
+
+ xstrncpy((char *)loopinfo64.lo_file_name, file, LO_NAME_SIZE);
+
+ if (encryption && *encryption) {
+ if (digits_only(encryption)) {
+ loopinfo64.lo_encrypt_type = atoi(encryption);
+ } else {
+ loopinfo64.lo_encrypt_type = LO_CRYPT_CRYPTOAPI;
+ snprintf((char *)loopinfo64.lo_crypt_name, LO_NAME_SIZE,
+ "%s", encryption);
+ }
+ }
+
+ loopinfo64.lo_offset = offset;
+
+
+ switch (loopinfo64.lo_encrypt_type) {
+ case LO_CRYPT_NONE:
+ loopinfo64.lo_encrypt_key_size = 0;
+ break;
+ case LO_CRYPT_XOR:
+ pass = xgetpass(pfd, "Password: ");
+ goto gotpass;
+ default:
+ pass = xgetpass(pfd, "Password: ");
+ gotpass:
+ memset(loopinfo64.lo_encrypt_key, 0, LO_KEY_SIZE);
+ xstrncpy((char *)loopinfo64.lo_encrypt_key, pass, LO_KEY_SIZE);
+ memset(pass, 0, strlen(pass));
+ loopinfo64.lo_encrypt_key_size = LO_KEY_SIZE;
+ }
+
+ if (ioctl(fd, LOOP_SET_FD, (void *)(size_t)ffd) < 0) {
+ perror("ioctl: LOOP_SET_FD");
+ return 1;
+ }
+ close (ffd);
+
+ i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
+ if (i)
+ perror("ioctl: LOOP_SET_STATUS64");
+ memset(&loopinfo64, 0, sizeof(loopinfo64));
+
+ if (i) {
+ ioctl (fd, LOOP_CLR_FD, 0);
+ close (fd);
+ return 1;
+ }
+ close (fd);
+
+ if (verbose > 1)
+ printf("set_loop(%s,%s,%llu): success\n",
+ device, file, offset);
+ return 0;
+}
+
+int del_loop (const char *device)
+{
+ int fd;
+
+ if ((fd = open (device, O_RDONLY)) < 0) {
+ int errsv = errno;
+ fprintf(stderr, "loop: can't delete device %s: %s\n",
+ device, strerror (errsv));
+ return 1;
+ }
+ if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
+ perror ("ioctl: LOOP_CLR_FD");
+ close (fd);
+ return 1;
+ }
+ close (fd);
+ if (verbose > 1)
+ printf("del_loop(%s): success\n", device);
+ return 0;
+}
+
+
+int verbose = 0;
+char *progname;
+
+static void usage(FILE *f)
+{
+ fprintf(f, "usage:\n\
+ %s loop_device # give info\n\
+ %s -d loop_device # delete\n\
+ %s -f # find unused\n\
+ %s -h # this help\n\
+ %s [-e encryption] [-o offset] {-f|loop_device} file # setup\n",
+ progname, progname, progname, progname, progname);
+ exit(f == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+char * xstrdup (const char *s) {
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL) {
+ fprintf(stderr, "not enough memory");
+ exit(1);
+ }
+
+ return t;
+}
+
+void error (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+}
+
+int main(int argc, char **argv)
+{
+ char *p, *offset, *encryption, *passfd, *device, *file;
+ int delete, find, c;
+ int res = 0;
+ int ro = 0;
+ int pfd = -1;
+ unsigned long long off;
+
+
+ delete = find = 0;
+ off = 0;
+ offset = encryption = passfd = NULL;
+
+ progname = argv[0];
+ if ((p = strrchr(progname, '/')) != NULL)
+ progname = p+1;
+
+ while ((c = getopt(argc, argv, "de:E:fho:p:v")) != -1) {
+ switch (c) {
+ case 'd':
+ delete = 1;
+ break;
+ case 'E':
+ case 'e':
+ encryption = optarg;
+ break;
+ case 'f':
+ find = 1;
+ break;
+ case 'h':
+ usage(stdout);
+ break;
+ case 'o':
+ offset = optarg;
+ break;
+ case 'p':
+ passfd = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage(stderr);
+ }
+ }
+
+ if (argc == 1) {
+ usage(stderr);
+ } else if (delete) {
+ if (argc != optind+1 || encryption || offset || find)
+ usage(stderr);
+ } else if (find) {
+ if (argc < optind || argc > optind+1)
+ usage(stderr);
+ } else {
+ if (argc < optind+1 || argc > optind+2)
+ usage(stderr);
+ }
+
+ if (find) {
+ device = find_unused_loop_device();
+ if (device == NULL)
+ return -1;
+ if (verbose)
+ printf("Loop device is %s\n", device);
+ if (argc == optind) {
+ printf("%s\n", device);
+ return 0;
+ }
+ file = argv[optind];
+ } else {
+ device = argv[optind];
+ if (argc == optind+1)
+ file = NULL;
+ else
+ file = argv[optind+1];
+ }
+
+ if (delete)
+ res = del_loop(device);
+ else if (file == NULL)
+ res = show_loop(device);
+ else {
+ if (offset && sscanf(offset, "%llu", &off) != 1)
+ usage(stderr);
+ if (passfd && sscanf(passfd, "%d", &pfd) != 1)
+ usage(stderr);
+ res = set_loop(device, file, off, encryption, pfd, &ro);
+ }
+ return res;
+}
diff --git a/usr/utils/ls.c b/usr/utils/ls.c
new file mode 100644
index 0000000..50af434
--- /dev/null
+++ b/usr/utils/ls.c
@@ -0,0 +1,223 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+
+#define STAT_ISSET(mode, mask) (((mode) & mask) == mask)
+
+static size_t max_linksiz = 128;
+static int max_nlinks = 1;
+static int max_size = 1;
+static int max_uid = 1;
+static int max_gid = 1;
+static int max_min = 1;
+static int max_maj = 1;
+
+static void do_preformat(const struct stat *st)
+{
+ int bytes;
+
+ bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_nlink);
+ if (bytes > max_nlinks)
+ max_nlinks = bytes;
+
+ bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_uid);
+ if (bytes > max_uid)
+ max_uid = bytes;
+
+ bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_gid);
+ if (bytes > max_gid)
+ max_gid = bytes;
+
+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+ bytes = snprintf(NULL, 0, "%u", major(st->st_rdev));
+ if (bytes > max_maj)
+ max_maj = bytes;
+
+ bytes = snprintf(NULL, 0, "%u", minor(st->st_rdev));
+ if (bytes > max_min)
+ max_min = bytes;
+
+ max_size = max_maj + max_min + 1;
+ } else {
+ bytes = snprintf(NULL, 0, "%ju", (uintmax_t) st->st_size);
+ if (bytes > max_size)
+ max_size = bytes;
+ }
+ return;
+}
+
+static void do_stat(const struct stat *st, int dir_fd, const char *path)
+{
+ char *fmt, *link_name;
+ int rc;
+
+ switch (st->st_mode & S_IFMT) {
+ case S_IFBLK:
+ putchar('b');
+ break;
+ case S_IFCHR:
+ putchar('c');
+ break;
+ case S_IFDIR:
+ putchar('d');
+ break;
+ case S_IFIFO:
+ putchar('p');
+ break;
+ case S_IFLNK:
+ putchar('l');
+ break;
+ case S_IFSOCK:
+ putchar('s');
+ break;
+ case S_IFREG:
+ putchar('-');
+ break;
+ default:
+ putchar('?');
+ break;
+ }
+ putchar(STAT_ISSET(st->st_mode, S_IRUSR) ? 'r' : '-');
+ putchar(STAT_ISSET(st->st_mode, S_IWUSR) ? 'w' : '-');
+
+ !STAT_ISSET(st->st_mode, S_ISUID) ?
+ putchar(STAT_ISSET(st->st_mode, S_IXUSR) ? 'x' : '-') :
+ putchar('S');
+
+ putchar(STAT_ISSET(st->st_mode, S_IRGRP) ? 'r' : '-');
+ putchar(STAT_ISSET(st->st_mode, S_IWGRP) ? 'w' : '-');
+
+ !STAT_ISSET(st->st_mode, S_ISGID) ?
+ putchar(STAT_ISSET(st->st_mode, S_IXGRP) ? 'x' : '-') :
+ putchar('S');
+
+ putchar(STAT_ISSET(st->st_mode, S_IROTH) ? 'r' : '-');
+ putchar(STAT_ISSET(st->st_mode, S_IWOTH) ? 'w' : '-');
+
+ !STAT_ISSET(st->st_mode, S_ISVTX) ?
+ putchar(STAT_ISSET(st->st_mode, S_IXOTH) ? 'x' : '-') :
+ putchar(S_ISDIR(st->st_mode) ? 't' : 'T');
+
+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+ rc = asprintf(&fmt, " %%%dju %%%dju %%%dju %%%du,%%%du %%s",
+ max_nlinks, max_uid, max_gid, max_maj, max_min);
+ if (rc == -1) {
+ perror("asprintf");
+ exit(1);
+ }
+ fprintf(stdout, fmt,
+ (uintmax_t) st->st_nlink,
+ (uintmax_t) st->st_uid,
+ (uintmax_t) st->st_gid,
+ major(st->st_rdev),
+ minor(st->st_rdev),
+ path);
+ } else {
+ rc = asprintf(&fmt, " %%%dju %%%dju %%%dju %%%dju %%s",
+ max_nlinks, max_uid, max_gid, max_size);
+ if (rc == -1) {
+ perror("asprintf");
+ exit(1);
+ }
+ fprintf(stdout, fmt,
+ (uintmax_t) st->st_nlink,
+ (uintmax_t) st->st_uid,
+ (uintmax_t) st->st_gid,
+ (uintmax_t) st->st_size,
+ path);
+ }
+ free(fmt);
+
+ if (S_ISLNK(st->st_mode)) {
+ link_name = malloc(max_linksiz);
+ if (link_name == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ rc = readlinkat(dir_fd, path, link_name, max_linksiz);
+ if (rc == -1) {
+ free(link_name);
+ perror("readlink");
+ exit(1);
+ }
+ link_name[rc] = '\0';
+ fprintf(stdout, " -> %s", link_name);
+ free(link_name);
+ }
+
+ putchar('\n');
+ return;
+}
+
+static void do_dir(const char *path, int preformat)
+{
+ DIR *dir;
+ int dir_fd;
+ struct dirent *dent;
+ struct stat st;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ perror(path);
+ exit(1);
+ }
+ dir_fd = dirfd(dir);
+
+ while ((dent = readdir(dir)) != NULL) {
+ if (fstatat(dir_fd, dent->d_name, &st,
+ AT_SYMLINK_NOFOLLOW)) {
+ perror(dent->d_name);
+ exit(1);
+ }
+ (preformat) ?
+ do_preformat(&st) :
+ do_stat(&st, dir_fd, dent->d_name);
+ }
+
+ closedir(dir);
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct stat st;
+
+ if (argc == 1) {
+ do_dir(".", 1);
+ do_dir(".", 0);
+ return 0;
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == 'h') {
+ fprintf(stdout, "Usage: ls [-h] [FILE ...]\n");
+ return 0;
+ }
+
+ if (lstat(argv[i], &st)) {
+ perror(argv[i]);
+ exit(1);
+ }
+
+ S_ISDIR(st.st_mode) ?
+ do_dir(argv[i], 1) :
+ do_preformat(&st);
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (lstat(argv[i], &st)) {
+ perror(argv[i]);
+ exit(1);
+ }
+
+ S_ISDIR(st.st_mode) ?
+ do_dir(argv[i], 0) :
+ do_stat(&st, AT_FDCWD, argv[i]);
+ }
+
+ return 0;
+}
diff --git a/usr/utils/minips.c b/usr/utils/minips.c
new file mode 100644
index 0000000..f48505f
--- /dev/null
+++ b/usr/utils/minips.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright 1998 by Albert Cahalan; all rights reserved.
+ * This file may be used subject to the terms and conditions of the
+ * GNU Library General Public License Version 2, or any later version
+ * at your option, as published by the Free Software Foundation.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ */
+
+/* This is a minimal /bin/ps, designed to be smaller than the old ps
+ * while still supporting some of the more important features of the
+ * new ps. (for total size, note that this ps does not need libproc)
+ * It is suitable for Linux-on-a-floppy systems only.
+ *
+ * Maintainers: do not compile or install for normal systems.
+ * Anyone needing this will want to tweak their compiler anyway.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <asm/param.h> /* HZ */
+
+static int P_euid;
+static int P_pid;
+static char P_cmd[16];
+static char P_state;
+static int P_ppid, P_pgrp, P_session, P_tty, P_tpgid;
+static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt,
+ P_utime, P_stime;
+static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_it_real_value;
+static unsigned long P_start_time, P_vsize;
+static long P_rss;
+static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack,
+ P_kstk_esp, P_kstk_eip;
+static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch;
+static unsigned long P_wchan, P_nswap, P_cnswap;
+
+#if 0
+static int screen_cols = 80;
+static int w_count;
+#endif
+
+static int want_one_pid;
+static const char *want_one_command;
+static int select_notty;
+static int select_all;
+
+static int ps_format;
+static int old_h_option;
+
+/* we only pretend to support this */
+static int show_args; /* implicit with -f and all BSD options */
+static int bsd_c_option; /* this option overrides the above */
+
+static int ps_argc; /* global argc */
+static char **ps_argv; /* global argv */
+static int thisarg; /* index into ps_argv */
+static char *flagptr; /* current location in ps_argv[thisarg] */
+
+#ifndef HZ
+#warning HZ not defined, assuming it is 100
+#define HZ 100
+#endif
+
+int page_shift; /* Page size as shift count */
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "-C select by command name (minimal ps only accepts one)\n"
+ "-p select by process ID (minimal ps only accepts one)\n"
+ "-e all processes (same as ax)\n"
+ "a all processes w/ tty, including other users\n"
+ "x processes w/o controlling ttys\n"
+ "-f full format\n"
+ "-j,j job control format\n"
+ "v virtual memory format\n"
+ "-l,l long format\n"
+ "u user-oriented format\n"
+ "-o user-defined format (limited support, only \"ps -o pid=\")\n"
+ "h no header\n"
+/*
+ "-A all processes (same as ax)\n"
+ "c true command name\n"
+ "-w,w wide output\n"
+*/
+ );
+ exit(1);
+}
+
+/*
+ * Return the next argument, or call the usage function.
+ * This handles both: -oFOO -o FOO
+ */
+static const char *get_opt_arg(void)
+{
+ const char *ret;
+ ret = flagptr + 1; /* assume argument is part of ps_argv[thisarg] */
+ if (*ret)
+ return ret;
+ if (++thisarg >= ps_argc)
+ usage(); /* there is nothing left */
+ /* argument is the new ps_argv[thisarg] */
+ ret = ps_argv[thisarg];
+ if (!ret || !*ret)
+ usage();
+ return ret;
+}
+
+/* return the PID, or 0 if nothing good */
+static void parse_pid(const char *str)
+{
+ char *endp;
+ int num;
+ if (!str)
+ goto bad;
+ num = strtol(str, &endp, 0);
+ if (*endp != '\0')
+ goto bad;
+ if (num < 1)
+ goto bad;
+ if (want_one_pid)
+ goto bad;
+ want_one_pid = num;
+ return;
+ bad:
+ usage();
+}
+
+/***************** parse SysV options, including Unix98 *****************/
+static void parse_sysv_option(void)
+{
+ do {
+ switch (*flagptr) {
+ /**** selection ****/
+ case 'C': /* end */
+ if (want_one_command)
+ usage();
+ want_one_command = get_opt_arg();
+ return; /* can't have any more options */
+ case 'p': /* end */
+ parse_pid(get_opt_arg());
+ return; /* can't have any more options */
+ case 'A':
+ case 'e':
+ select_all++;
+ select_notty++;
+ case 'w': /* here for now, since the real one is not used */
+ break;
+ /**** output format ****/
+ case 'f':
+ show_args = 1;
+ /* FALL THROUGH */
+ case 'j':
+ case 'l':
+ if (ps_format)
+ usage();
+ ps_format = *flagptr;
+ break;
+ case 'o': /* end */
+ /* We only support a limited form: "ps -o pid=" (yes, just "pid=") */
+ if (strcmp(get_opt_arg(), "pid="))
+ usage();
+ if (ps_format)
+ usage();
+ ps_format = 'o';
+ old_h_option++;
+ return; /* can't have any more options */
+ /**** other stuff ****/
+#if 0
+ case 'w':
+ w_count++;
+ break;
+#endif
+ default:
+ usage();
+ } /* switch */
+ } while (*++flagptr);
+}
+
+/************************* parse BSD options **********************/
+static void parse_bsd_option(void)
+{
+ do {
+ switch (*flagptr) {
+ /**** selection ****/
+ case 'a':
+ select_all++;
+ break;
+ case 'x':
+ select_notty++;
+ break;
+ case 'p': /* end */
+ parse_pid(get_opt_arg());
+ return; /* can't have any more options */
+ /**** output format ****/
+ case 'j':
+ case 'l':
+ case 'u':
+ case 'v':
+ if (ps_format)
+ usage();
+ ps_format = 0x80 | *flagptr; /* use 0x80 to tell BSD from SysV */
+ break;
+ /**** other stuff ****/
+ case 'c':
+ bsd_c_option++;
+#if 0
+ break;
+#endif
+ case 'w':
+#if 0
+ w_count++;
+#endif
+ break;
+ case 'h':
+ old_h_option++;
+ break;
+ default:
+ usage();
+ } /* switch */
+ } while (*++flagptr);
+}
+
+#if 0
+/* not used yet */
+static void choose_dimensions(void)
+{
+ struct winsize ws;
+ char *columns;
+ /* screen_cols is 80 by default */
+ if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 30)
+ screen_cols = ws.ws_col;
+ columns = getenv("COLUMNS");
+ if (columns && *columns) {
+ long t;
+ char *endptr;
+ t = strtol(columns, &endptr, 0);
+ if (!*endptr && (t > 30) && (t < (long)999999999))
+ screen_cols = (int)t;
+ }
+ if (w_count && (screen_cols < 132))
+ screen_cols = 132;
+ if (w_count > 1)
+ screen_cols = 999999999;
+}
+#endif
+
+static void arg_parse(int argc, char *argv[])
+{
+ int sel = 0; /* to verify option sanity */
+ ps_argc = argc;
+ ps_argv = argv;
+ thisarg = 0;
+ /**** iterate over the args ****/
+ while (++thisarg < ps_argc) {
+ flagptr = ps_argv[thisarg];
+ switch (*flagptr) {
+ case '0'...'9':
+ show_args = 1;
+ parse_pid(flagptr);
+ break;
+ case '-':
+ flagptr++;
+ parse_sysv_option();
+ break;
+ default:
+ show_args = 1;
+ parse_bsd_option();
+ break;
+ }
+ }
+ /**** sanity check and clean-up ****/
+ if (want_one_pid)
+ sel++;
+ if (want_one_command)
+ sel++;
+ if (select_notty || select_all)
+ sel++;
+ if (sel > 1 || select_notty > 1 || select_all > 1 || bsd_c_option > 1
+ || old_h_option > 1)
+ usage();
+ if (bsd_c_option)
+ show_args = 0;
+}
+
+/* return 1 if it works, or 0 for failure */
+static int stat2proc(int pid)
+{
+ char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
+ int num;
+ int fd;
+ char *tmp;
+ struct stat sb; /* stat() used to get EUID */
+
+ snprintf(buf, 32, "/proc/%d/stat", pid);
+ fd = open(buf, O_RDONLY, 0);
+ if (fd == -1)
+ return 0;
+ num = read(fd, buf, sizeof buf - 1);
+ fstat(fd, &sb);
+ P_euid = sb.st_uid;
+ close(fd);
+ if (num < 80)
+ return 0;
+ buf[num] = '\0';
+ tmp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
+ *tmp = '\0'; /* replace trailing ')' with NUL */
+ /* parse these two strings separately, skipping the leading "(". */
+ memset(P_cmd, 0, sizeof P_cmd); /* clear */
+ sscanf(buf, "%d (%15c", &P_pid, P_cmd); /* comm[16] in kernel */
+ num = sscanf(tmp + 2, /* skip space after ')' too */
+ "%c " "%d %d %d %d %d " "%lu %lu %lu %lu %lu %lu %lu " "%ld %ld %ld %ld %ld %ld " "%lu %lu " "%ld " "%lu %lu %lu %lu %lu %lu " "%u %u %u %u " /* no use for RT signals */
+ "%lu %lu %lu",
+ &P_state,
+ &P_ppid, &P_pgrp, &P_session, &P_tty, &P_tpgid,
+ &P_flags, &P_min_flt, &P_cmin_flt, &P_maj_flt, &P_cmaj_flt,
+ &P_utime, &P_stime, &P_cutime, &P_cstime, &P_priority,
+ &P_nice, &P_timeout, &P_it_real_value, &P_start_time,
+ &P_vsize, &P_rss, &P_rss_rlim, &P_start_code, &P_end_code,
+ &P_start_stack, &P_kstk_esp, &P_kstk_eip, &P_signal,
+ &P_blocked, &P_sigignore, &P_sigcatch, &P_wchan, &P_nswap,
+ &P_cnswap);
+/* fprintf(stderr, "stat2proc converted %d fields.\n",num); */
+ P_vsize /= 1024;
+ P_rss <<= page_shift - 10;
+ if (num < 30)
+ return 0;
+ if (P_pid != pid)
+ return 0;
+ return 1;
+}
+
+static const char *do_time(unsigned long t)
+{
+ int hh, mm, ss;
+ static char buf[32];
+ int cnt = 0;
+ t /= HZ;
+ ss = t % 60;
+ t /= 60;
+ mm = t % 60;
+ t /= 60;
+ hh = t % 24;
+ t /= 24;
+ if (t)
+ cnt = snprintf(buf, sizeof buf, "%d-", (int)t);
+ snprintf(cnt + buf, sizeof(buf) - cnt, "%02d:%02d:%02d", hh, mm, ss);
+ return buf;
+}
+
+static void print_proc(void)
+{
+ char tty[16];
+ snprintf(tty, sizeof tty, "%3d,%-3d", (P_tty >> 8) & 0xff,
+ P_tty & 0xff);
+ switch (ps_format) {
+ case 0:
+ printf("%5d %s %s", P_pid, tty, do_time(P_utime + P_stime));
+ break;
+ case 'o':
+ printf("%d\n", P_pid);
+ return; /* don't want the command */
+ case 'l':
+ printf("%03x %c %5d %5d %5d - %3d %3d - "
+ "%5ld %06x %s %s",
+ (unsigned)P_flags & 0x777, P_state, P_euid, P_pid,
+ P_ppid, (int)P_priority, (int)P_nice,
+ P_vsize >> (page_shift - 10),
+ (unsigned)(P_wchan & 0xffffff), tty,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ case 'f':
+ printf("%5d %5d %5d - - %s %s",
+ P_euid, P_pid, P_ppid, tty, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'j':
+ printf("%5d %5d %5d %s %s",
+ P_pid, P_pgrp, P_session, tty, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'u' | 0x80:
+ printf("%5d %5d - - %5ld %5ld %s %c - %s",
+ P_euid, P_pid, P_vsize, P_rss, tty, P_state,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ case 'v' | 0x80:
+ printf("%5d %s %c %s %6d - - %5d -",
+ P_pid, tty, P_state, do_time(P_utime + P_stime),
+ (int)P_maj_flt, (int)P_rss);
+ break;
+ case 'j' | 0x80:
+ printf("%5d %5d %5d %5d %s %5d %c %5d %s",
+ P_ppid, P_pid, P_pgrp, P_session, tty, P_tpgid, P_state,
+ P_euid, do_time(P_utime + P_stime)
+ );
+ break;
+ case 'l' | 0x80:
+ printf("%03x %5d %5d %5d %3d %3d "
+ "%5ld %4ld %06x %c %s %s",
+ (unsigned)P_flags & 0x777, P_euid, P_pid, P_ppid,
+ (int)P_priority, (int)P_nice, P_vsize, P_rss,
+ (unsigned)(P_wchan & 0xffffff), P_state, tty,
+ do_time(P_utime + P_stime)
+ );
+ break;
+ default:
+ break;
+ }
+ if (show_args)
+ printf(" [%s]\n", P_cmd);
+ else
+ printf(" %s\n", P_cmd);
+}
+
+int main(int argc, char *argv[])
+{
+ arg_parse(argc, argv);
+
+ page_shift = __getpageshift();
+
+#if 0
+ choose_dimensions();
+#endif
+ if (!old_h_option) {
+ const char *head;
+ switch (ps_format) {
+ default: /* can't happen */
+ case 0:
+ head = " PID TTY TIME CMD";
+ break;
+ case 'l':
+ head =
+ " F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD";
+ break;
+ case 'f':
+ head =
+ " UID PID PPID C STIME TTY TIME CMD";
+ break;
+ case 'j':
+ head = " PID PGID SID TTY TIME CMD";
+ break;
+ case 'u' | 0x80:
+ head =
+ " UID PID %CPU %MEM VSZ RSS TTY S START TIME COMMAND";
+ break;
+ case 'v' | 0x80:
+ head =
+ " PID TTY S TIME MAJFL TRS DRS RSS %MEM COMMAND";
+ break;
+ case 'j' | 0x80:
+ head =
+ " PPID PID PGID SID TTY TPGID S UID TIME COMMAND";
+ break;
+ case 'l' | 0x80:
+ head =
+ " F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND";
+ break;
+ }
+ printf("%s\n", head);
+ }
+ if (want_one_pid) {
+ if (stat2proc(want_one_pid))
+ print_proc();
+ else
+ exit(1);
+ } else {
+ struct dirent *ent; /* dirent handle */
+ DIR *dir;
+ int ouruid;
+ int found_a_proc;
+ found_a_proc = 0;
+ ouruid = getuid();
+ dir = opendir("/proc");
+ if (!dir)
+ exit(1);
+ while ((ent = readdir(dir))) {
+ if (*ent->d_name < '0' || *ent->d_name > '9')
+ continue;
+ if (!stat2proc(atoi(ent->d_name)))
+ continue;
+ if (want_one_command) {
+ if (strcmp(want_one_command, P_cmd))
+ continue;
+ } else {
+ if (!select_notty && P_tty == -1)
+ continue;
+ if (!select_all && P_euid != ouruid)
+ continue;
+ }
+ found_a_proc++;
+ print_proc();
+ }
+ closedir(dir);
+ exit(!found_a_proc);
+ }
+ return 0;
+}
diff --git a/usr/utils/mkdir.c b/usr/utils/mkdir.c
new file mode 100644
index 0000000..af241ef
--- /dev/null
+++ b/usr/utils/mkdir.c
@@ -0,0 +1,154 @@
+#include <sys/stat.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>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode, subdir_mode;
+static int p_flag;
+
+char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s [-p] [-m mode] dir...\n", progname);
+ exit(1);
+}
+
+static int make_one_dir(char *dir, mode_t mode)
+{
+ struct stat stbuf;
+
+ if (mkdir(dir, mode) == -1) {
+ int err = errno;
+
+ /*
+ * Ignore the error if it all of the following
+ * are satisfied:
+ * - error was EEXIST
+ * - -p was specified
+ * - stat indicates that its a directory
+ */
+ if (p_flag && errno == EEXIST &&
+ stat(dir, &stbuf) == 0 && S_ISDIR(stbuf.st_mode))
+ return 1;
+ errno = err;
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+static int make_dir(char *dir)
+{
+ int ret;
+
+ if (p_flag) {
+ char *s, *p;
+
+ /*
+ * Recurse each directory, trying to make it
+ * as we go. Should we check to see if it
+ * exists, and if so if it's a directory
+ * before calling mkdir?
+ */
+ s = dir;
+ while ((p = strchr(s, '/')) != NULL) {
+ /*
+ * Ignore the leading /
+ */
+ if (p != dir) {
+ *p = '\0';
+
+ /*
+ * Make the intermediary directory. POSIX
+ * says that these directories are created
+ * with umask,u+wx
+ */
+ if (make_one_dir(dir, subdir_mode) == -1)
+ return -1;
+
+ *p = '/';
+ }
+ s = p + 1;
+ }
+ }
+
+ /*
+ * Make the final target. Only complain if the
+ * target already exists if -p was not specified.
+ * This is created with the asked for mode & ~umask
+ */
+ ret = make_one_dir(dir, leaf_mode);
+ if (ret == -1)
+ return -1;
+
+ /*
+ * We might not set all the permission bits. Do that
+ * here (but only if we did create it.)
+ */
+ if (ret == 0 && chmod(dir, leaf_mode) == -1) {
+ int err_save = errno;
+
+ /*
+ * We failed, remove the directory we created
+ */
+ rmdir(dir);
+ errno = err_save;
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, ret = 0;
+ mode_t saved_umask;
+
+ progname = argv[0];
+
+ saved_umask = umask(0);
+ leaf_mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~saved_umask;
+ subdir_mode = (saved_umask ^ (S_IRWXU | S_IRWXG | S_IRWXO))
+ | S_IWUSR | S_IXUSR;
+
+ do {
+ c = getopt(argc, argv, "pm:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ leaf_mode =
+ parse_file_mode(optarg, leaf_mode, saved_umask);
+ break;
+ case 'p':
+ p_flag = 1;
+ break;
+
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ usage();
+ }
+ } while (1);
+
+ if (optind == argc)
+ usage();
+
+ while (optind < argc) {
+ if (make_dir(argv[optind]))
+ ret = 255; /* seems to be what gnu mkdir does */
+ optind++;
+ }
+
+ return ret;
+}
diff --git a/usr/utils/mkfifo.c b/usr/utils/mkfifo.c
new file mode 100644
index 0000000..5a758b2
--- /dev/null
+++ b/usr/utils/mkfifo.c
@@ -0,0 +1,70 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_mode.h"
+
+static mode_t leaf_mode;
+
+char *progname;
+
+static int make_fifo(char *dir)
+{
+ if (mkfifo(dir, leaf_mode)) {
+ /*
+ * We failed, remove the directory we created.
+ */
+ fprintf(stderr, "%s: ", progname);
+ perror(dir);
+ return -1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, ret = 0;
+ mode_t saved_umask;
+
+ progname = argv[0];
+
+ saved_umask = umask(0);
+ leaf_mode =
+ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) &
+ ~saved_umask;
+
+ do {
+ c = getopt(argc, argv, "m:");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'm':
+ leaf_mode =
+ parse_file_mode(optarg, leaf_mode, saved_umask);
+ break;
+
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-m mode] file...\n", progname);
+ exit(1);
+ }
+
+ while (optind < argc) {
+ if (make_fifo(argv[optind]))
+ ret = 255; /* seems to be what gnu mkdir does */
+ optind++;
+ }
+
+ return ret;
+}
diff --git a/usr/utils/mknod.c b/usr/utils/mknod.c
new file mode 100644
index 0000000..fa7ac7a
--- /dev/null
+++ b/usr/utils/mknod.c
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s [-m mode] name {b|c|p} major minor\n",
+ progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ char *name, *type, typec, *endp;
+ unsigned int major_num, minor_num;
+ mode_t mode, mode_set = 0;
+ dev_t dev;
+
+ progname = *argv++;
+ if (argc == 1)
+ usage();
+
+ if (argv[0][0] == '-' && argv[0][1] == 'm' && !argv[0][2]) {
+ mode_set = strtoul(argv[1], &endp, 8);
+ argv += 2;
+ }
+
+ name = *argv++;
+ if (!name)
+ usage();
+
+ type = *argv++;
+ if (!type || !type[0] || type[1])
+ usage();
+ typec = type[0];
+
+ mode = 0;
+ switch (typec) {
+ case 'c':
+ mode = S_IFCHR;
+ break;
+ case 'b':
+ mode = S_IFBLK;
+ break;
+ case 'p':
+ mode = S_IFIFO;
+ break;
+ default:
+ usage();
+ }
+
+ if (mode == S_IFIFO) {
+ dev = 0;
+ } else {
+ if (!argv[0] || !argv[1])
+ usage();
+
+ major_num = strtol(*argv++, &endp, 0);
+ if (*endp != '\0')
+ usage();
+ minor_num = strtol(*argv++, &endp, 0);
+ if (*endp != '\0')
+ usage();
+ dev = makedev(major_num, minor_num);
+ }
+
+ if (*argv)
+ usage();
+
+ if (mknod(name, mode|0666, dev) == -1) {
+ perror("mknod");
+ exit(1);
+ }
+
+ if (mode_set && chmod(name, mode_set)) {
+ perror("chmod");
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/usr/utils/mount_main.c b/usr/utils/mount_main.c
new file mode 100644
index 0000000..0d299c4
--- /dev/null
+++ b/usr/utils/mount_main.c
@@ -0,0 +1,156 @@
+/*
+ * by rmk
+ */
+#include <sys/mount.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <mntent.h>
+
+#include "mount_opts.h"
+
+#define _PATH_MOUNTED "/etc/mtab"
+#define _PATH_PROC_MOUNTS "/proc/mounts"
+
+char *progname;
+
+static struct extra_opts extra;
+static unsigned long rwflag;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s [-r] [-w] [-o options] [-t type] [-f] [-i] "
+ "[-n] device directory\n", progname);
+ exit(1);
+}
+
+static __noreturn print_mount(char *type)
+{
+ FILE *mfp;
+ struct mntent *mnt;
+
+ mfp = setmntent(_PATH_PROC_MOUNTS, "r");
+ if (!mfp)
+ mfp = setmntent(_PATH_MOUNTED, "r");
+ if (!mfp)
+ perror("setmntent");
+
+ while ((mnt = getmntent(mfp)) != NULL) {
+ if (mnt->mnt_fsname && !strncmp(mnt->mnt_fsname, "no", 2))
+ continue;
+ if (type && mnt->mnt_type && strcmp(type, mnt->mnt_type))
+ continue;
+ printf("%s on %s", mnt->mnt_fsname, mnt->mnt_dir);
+ if (mnt->mnt_type != NULL && *mnt->mnt_type != '\0')
+ printf(" type %s", mnt->mnt_type);
+ if (mnt->mnt_opts != NULL && *mnt->mnt_opts != '\0')
+ printf(" (%s)", mnt->mnt_opts);
+ printf("\n");
+ }
+ endmntent(mfp);
+ exit(0);
+}
+
+static int
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data)
+{
+ char *s;
+ int error = 0;
+
+ while ((s = strsep(&type, ",")) != NULL) {
+retry:
+ if (mount(dev, dir, s, rwflag, data) == -1) {
+ error = errno;
+ /*
+ * If the filesystem is not found, or the
+ * superblock is invalid, try the next.
+ */
+ if (error == ENODEV || error == EINVAL)
+ continue;
+
+ /*
+ * If we get EACCESS, and we're trying to
+ * mount readwrite and this isn't a remount,
+ * try read only.
+ */
+ if (error == EACCES &&
+ (rwflag & (MS_REMOUNT | MS_RDONLY)) == 0) {
+ rwflag |= MS_RDONLY;
+ goto retry;
+ }
+ } else {
+ error = 0;
+ }
+ break;
+ }
+
+ if (error) {
+ errno = error;
+ perror("mount");
+ return 255;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *type = NULL;
+ int c;
+
+ progname = argv[0];
+ rwflag = MS_VERBOSE;
+
+ do {
+ c = getopt(argc, argv, "fhino:rt:w");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ /* we can't edit /etc/mtab yet anyway; exit */
+ exit(0);
+ case 'i':
+ /* ignore for now; no support for mount helpers */
+ break;
+ case 'h':
+ usage();
+ case 'n':
+ /* no mtab writing */
+ break;
+ case 'o':
+ rwflag = parse_mount_options(optarg, rwflag, &extra);
+ break;
+ case 'r':
+ rwflag |= MS_RDONLY;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'w':
+ rwflag &= ~MS_RDONLY;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind == argc)
+ print_mount(type);
+
+ /*
+ * If remount, bind or move was specified, then we don't
+ * have a "type" as such. Use the dummy "none" type.
+ */
+ if (rwflag & MS_TYPE)
+ type = "none";
+
+ if (optind + 2 != argc || type == NULL)
+ usage();
+
+ return do_mount(argv[optind], argv[optind + 1], type, rwflag,
+ extra.str);
+}
diff --git a/usr/utils/mount_opts.c b/usr/utils/mount_opts.c
new file mode 100644
index 0000000..bb26c7d
--- /dev/null
+++ b/usr/utils/mount_opts.c
@@ -0,0 +1,102 @@
+/*
+ * by rmk
+ *
+ * Decode mount options.
+ */
+#include <sys/mount.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mount_opts.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static const struct mount_opts options[] = {
+ /* name mask set noset */
+ {"async", MS_SYNCHRONOUS, 0, MS_SYNCHRONOUS},
+ {"atime", MS_NOATIME, 0, MS_NOATIME},
+ {"bind", MS_TYPE, MS_BIND, 0,},
+ {"dev", MS_NODEV, 0, MS_NODEV},
+ {"diratime", MS_NODIRATIME, 0, MS_NODIRATIME},
+ {"dirsync", MS_DIRSYNC, MS_DIRSYNC, 0},
+ {"exec", MS_NOEXEC, 0, MS_NOEXEC},
+ {"move", MS_TYPE, MS_MOVE, 0},
+ {"nodev", MS_NODEV, MS_NODEV, 0},
+ {"noexec", MS_NOEXEC, MS_NOEXEC, 0},
+ {"nosuid", MS_NOSUID, MS_NOSUID, 0},
+ {"recurse", MS_REC, MS_REC, 0},
+ {"remount", MS_TYPE, MS_REMOUNT, 0},
+ {"ro", MS_RDONLY, MS_RDONLY, 0},
+ {"rw", MS_RDONLY, 0, MS_RDONLY},
+ {"suid", MS_NOSUID, 0, MS_NOSUID},
+ {"sync", MS_SYNCHRONOUS, MS_SYNCHRONOUS, 0},
+ {"verbose", MS_VERBOSE, MS_VERBOSE, 0},
+};
+
+static void add_extra_option(struct extra_opts *extra, char *s)
+{
+ int len = strlen(s);
+ int newlen = extra->used_size + len;
+
+ if (extra->str)
+ len++; /* +1 for ',' */
+
+ if (newlen >= extra->alloc_size) {
+ char *new;
+
+ new = realloc(extra->str, newlen + 1); /* +1 for NUL */
+ if (!new)
+ return;
+
+ extra->str = new;
+ extra->end = extra->str + extra->used_size;
+ extra->alloc_size = newlen;
+ }
+
+ if (extra->used_size) {
+ *extra->end = ',';
+ extra->end++;
+ }
+ strcpy(extra->end, s);
+ extra->used_size += len;
+
+}
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra)
+{
+ char *s;
+
+ while ((s = strsep(&arg, ",")) != NULL) {
+ char *opt = s;
+ unsigned int i;
+ int res, no = s[0] == 'n' && s[1] == 'o';
+
+ if (no)
+ s += 2;
+
+ for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
+ res = strcmp(s, options[i].str);
+
+ if (res == 0) {
+ rwflag &= ~options[i].rwmask;
+ if (no)
+ rwflag |= options[i].rwnoset;
+ else
+ rwflag |= options[i].rwset;
+ }
+ if (res <= 0)
+ break;
+ }
+
+ if (res != 0 && s[0]) {
+ if (!strcmp(opt, "defaults"))
+ rwflag &= ~(MS_RDONLY|MS_NOSUID|MS_NODEV|
+ MS_NOEXEC|MS_SYNCHRONOUS);
+ else
+ add_extra_option(extra, opt);
+ }
+ }
+
+ return rwflag;
+}
diff --git a/usr/utils/mount_opts.h b/usr/utils/mount_opts.h
new file mode 100644
index 0000000..cf47cae
--- /dev/null
+++ b/usr/utils/mount_opts.h
@@ -0,0 +1,26 @@
+#ifndef UTILS_MOUNT_OPTS_H
+#define UTILS_MOUNT_OPTS_H
+
+struct mount_opts {
+ const char str[8];
+ unsigned long rwmask;
+ unsigned long rwset;
+ unsigned long rwnoset;
+};
+
+struct extra_opts {
+ char *str;
+ char *end;
+ int used_size;
+ int alloc_size;
+};
+
+/*
+ * These options define the function of "mount(2)".
+ */
+#define MS_TYPE (MS_REMOUNT|MS_BIND|MS_MOVE)
+
+unsigned long
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra);
+
+#endif /* UTILS_MOUNT_OPTS_H */
diff --git a/usr/utils/mv.c b/usr/utils/mv.c
new file mode 100644
index 0000000..e3f38ed
--- /dev/null
+++ b/usr/utils/mv.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/limits.h>
+
+int main(int argc, char *argv[])
+{
+ int c, f;
+ char *p;
+ struct stat sb;
+
+ f = 0;
+ do {
+ c = getopt(argc, argv, "f");
+ if (c == EOF)
+ break;
+
+ switch (c) {
+
+ case 'f':
+ f = 1;
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ argv[0], optopt);
+ return 1;
+ }
+
+ } while (1);
+
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [-f] source dest\n", argv[0]);
+ return 1;
+ }
+
+ memset(&sb, 0, sizeof(struct stat));
+ if (stat(argv[argc - 1], &sb) < 0 && argc - optind > 2) {
+ if (!(S_ISDIR(sb.st_mode))) {
+ fprintf(stderr,
+ "multiple targets and %s is not a directory\n",
+ argv[argc - 1]);
+ return 1;
+ }
+ }
+
+ for (c = optind; c < argc - 1; c++) {
+ char target[PATH_MAX];
+
+ p = strrchr(argv[c], '/');
+ p++;
+
+ if (S_ISDIR(sb.st_mode))
+ snprintf(target, PATH_MAX, "%s/%s", argv[argc - 1], p);
+ else
+ snprintf(target, PATH_MAX, "%s", argv[argc - 1]);
+
+ if (f)
+ unlink(target);
+
+ if (rename(argv[c], target) == -1)
+ perror(target);
+ }
+
+ return 0;
+}
diff --git a/usr/utils/nuke.c b/usr/utils/nuke.c
new file mode 100644
index 0000000..93a04af
--- /dev/null
+++ b/usr/utils/nuke.c
@@ -0,0 +1,121 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2006 H. Peter Anvin - All Rights Reserved
+ *
+ * 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, 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 AUTHORS OR 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Simple program which does the same thing as rm -rf, except it takes
+ * no options and can therefore not get confused by filenames starting
+ * with -. Similarly, an empty list of inputs is assumed to mean don't
+ * do anything.
+ */
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static const char *program;
+
+static int nuke(const char *what);
+
+static int nuke_dirent(int len, const char *dir, const char *name)
+{
+ int bytes = len + strlen(name) + 2;
+ char path[bytes];
+ int xlen;
+
+ xlen = snprintf(path, bytes, "%s/%s", dir, name);
+ assert(xlen < bytes);
+
+ return nuke(path);
+}
+
+/* Wipe the contents of a directory, but not the directory itself */
+static int nuke_dir(const char *what)
+{
+ int len = strlen(what);
+ DIR *dir;
+ struct dirent *d;
+ int err = 0;
+
+ dir = opendir(what);
+ if (!dir) {
+ /* EACCES means we can't read it. Might be empty and removable;
+ if not, the rmdir() in nuke() will trigger an error. */
+ return (errno == EACCES) ? 0 : errno;
+ }
+
+ while ((d = readdir(dir))) {
+ /* Skip . and .. */
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+
+ err = nuke_dirent(len, what, d->d_name);
+ if (err) {
+ closedir(dir);
+ return err;
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static int nuke(const char *what)
+{
+ int rv;
+ int err = 0;
+
+ rv = unlink(what);
+ if (rv < 0) {
+ if (errno == EISDIR) {
+ /* It's a directory. */
+ err = nuke_dir(what);
+ if (!err)
+ rmdir(what);
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ program = argv[0];
+
+ for (i = 1; i < argc; i++)
+ nuke(argv[i]);
+
+ return 0;
+}
diff --git a/usr/utils/pivot_root.c b/usr/utils/pivot_root.c
new file mode 100644
index 0000000..41b2ea0
--- /dev/null
+++ b/usr/utils/pivot_root.c
@@ -0,0 +1,19 @@
+/* Change the root file system */
+
+/* Written 2000 by Werner Almesberger */
+
+#include <stdio.h>
+#include <sys/mount.h>
+
+int main(int argc, const char **argv)
+{
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s new_root put_old\n", argv[0]);
+ return 1;
+ }
+ if (pivot_root(argv[1], argv[2]) < 0) {
+ perror("pivot_root");
+ return 1;
+ }
+ return 0;
+}
diff --git a/usr/utils/readlink.c b/usr/utils/readlink.c
new file mode 100644
index 0000000..1f16c02
--- /dev/null
+++ b/usr/utils/readlink.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+const char *progname;
+
+static __noreturn usage(void)
+{
+ fprintf(stderr, "Usage: %s [-f] link...\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int c, f_flag = 0;
+ const char *name;
+ char link_name[PATH_MAX];
+ int rv;
+
+ progname = argv[0];
+
+ do {
+ c = getopt(argc, argv, "f");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ f_flag = 1;
+ break;
+
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ usage();
+ }
+ } while (1);
+
+ if (optind == argc)
+ usage();
+
+ argv += optind;
+ while ((name = *argv++)) {
+ if (f_flag)
+ rv = realpath(name, link_name) ? strlen(link_name) : -1;
+ else
+ rv = readlink(name, link_name, sizeof link_name - 1);
+ if (rv < 0) {
+ perror(name);
+ exit(1);
+ }
+ link_name[rv] = '\n';
+ _fwrite(link_name, rv+1, stdout);
+ }
+
+ return 0;
+}
diff --git a/usr/utils/sleep.c b/usr/utils/sleep.c
new file mode 100644
index 0000000..991cdbe
--- /dev/null
+++ b/usr/utils/sleep.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+ struct timespec ts;
+ char *p;
+
+ if (argc != 2)
+ goto err;
+
+ p = strtotimespec(argv[1], &ts);
+ if (*p)
+ goto err;
+
+ while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
+ ;
+
+ return 0;
+
+err:
+ fprintf(stderr, "Usage: %s seconds[.fraction]\n", argv[0]);
+ return 1;
+}
diff --git a/usr/utils/sync.c b/usr/utils/sync.c
new file mode 100644
index 0000000..de3093c
--- /dev/null
+++ b/usr/utils/sync.c
@@ -0,0 +1,7 @@
+#include <unistd.h>
+
+int main(void)
+{
+ sync();
+ return 0;
+}
diff --git a/usr/utils/true.c b/usr/utils/true.c
new file mode 100644
index 0000000..31dbf45
--- /dev/null
+++ b/usr/utils/true.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/usr/utils/umount.c b/usr/utils/umount.c
new file mode 100644
index 0000000..41275f7
--- /dev/null
+++ b/usr/utils/umount.c
@@ -0,0 +1,51 @@
+/*
+ * by rmk
+ */
+#include <sys/mount.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *progname;
+
+int main(int argc, char *argv[])
+{
+ int c, flag = 0;
+
+ progname = argv[0];
+
+ do {
+ c = getopt(argc, argv, "fli");
+ if (c == EOF)
+ break;
+ switch (c) {
+ case 'f':
+ flag |= MNT_FORCE;
+ break;
+ case 'l':
+ flag |= MNT_DETACH;
+ break;
+ case 'i':
+ /* ignore for now; no support for umount helpers */
+ break;
+ case '?':
+ fprintf(stderr, "%s: invalid option -%c\n",
+ progname, optopt);
+ exit(1);
+ }
+ } while (1);
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "Usage: %s [-f] [-l] [-i] mntpoint\n",
+ progname);
+ return 1;
+ }
+
+ if (umount2(argv[optind], flag) == -1) {
+ perror("umount2");
+ return 255;
+ }
+
+ return 0;
+}
diff --git a/usr/utils/uname.c b/usr/utils/uname.c
new file mode 100644
index 0000000..6ea4dbe
--- /dev/null
+++ b/usr/utils/uname.c
@@ -0,0 +1,155 @@
+/*
+ * by tlh
+ *
+ * The uname program for system information: kernel name, kernel
+ * release, kernel release, machine, processor, platform, os and
+ * hostname.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+
+enum uname_fields {
+ UN_SYSNAME,
+ UN_NODENAME,
+ UN_RELEASE,
+ UN_VERSION,
+ UN_MACHINE,
+#if NOT_IMPLEMENTED_PROCESSOR
+ UN_PROCESSOR,
+#endif
+ UN_HARDWARE,
+#if NOT_IMPLEMENTED_OS
+ UN_OS,
+#endif
+ UN_NR_FIELDS
+};
+
+static void usage(FILE *stream, const char *progname)
+{
+ fprintf(stream,
+ "Usage: %s [OPTION] . . .\n"
+ "Print system information, No options defaults to -s.\n"
+ "\n"
+ " -a print all the information in the same order as follows below\n"
+ " -s kernel name\n"
+ " -n network node name (hostname)\n"
+ " -r kernel release\n"
+ " -v kernel version\n" " -m machine hardware name\n"
+#if NOT_IMPLEMENTED_PROCESSOR
+ " -p processor type\n"
+#endif
+ " -i hardware platform\n"
+#if NOT_IMPLEMENTED_OS
+ " -o operating system\n"
+#endif
+ "\n" " -h help/usage\n" "\n", progname);
+}
+
+static char *make_hardware(const char *machine)
+{
+ char *hardware;
+
+ hardware = strdup(machine);
+ if (!hardware) {
+ fprintf(stderr, "strdup() failed: %s\n", strerror(errno));
+ goto end;
+ }
+ if (strlen(hardware) == 4
+ && hardware[0] == 'i' && hardware[2] == '8' && hardware[3] == '6') {
+ hardware[1] = '3';
+ }
+end:
+ return hardware;
+}
+
+int main(int argc, char *argv[])
+{
+ int ec = 1;
+ int opt;
+ int i;
+ int nr_pr;
+ struct utsname buf;
+ char *uname_fields[UN_NR_FIELDS] = { NULL };
+
+ if (-1 == uname(&buf)) {
+ fprintf(stderr, "uname() failure: %s\n", strerror(errno));
+ goto end;
+ }
+
+ if (1 == argc)
+ /* no options given - default to -s */
+ uname_fields[UN_SYSNAME] = buf.sysname;
+
+ while ((opt = getopt(argc, argv, "asnrvmpioh")) != -1) {
+ switch (opt) {
+ case 'a':
+ uname_fields[UN_SYSNAME] = buf.sysname;
+ uname_fields[UN_NODENAME] = buf.nodename;
+ uname_fields[UN_RELEASE] = buf.release;
+ uname_fields[UN_VERSION] = buf.version;
+ uname_fields[UN_MACHINE] = buf.machine;
+ uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+ if (!uname_fields[UN_HARDWARE])
+ goto end;
+ break;
+ case 's':
+ uname_fields[UN_SYSNAME] = buf.sysname;
+ break;
+ case 'n':
+ uname_fields[UN_NODENAME] = buf.nodename;
+ break;
+ case 'r':
+ uname_fields[UN_RELEASE] = buf.release;
+ break;
+ case 'v':
+ uname_fields[UN_VERSION] = buf.version;
+ break;
+ case 'm':
+ uname_fields[UN_MACHINE] = buf.machine;
+ break;
+#if NOT_IMPLEMENTED_PROCESSOR
+ case 'p':
+ break;
+#endif
+ case 'i':
+ uname_fields[UN_HARDWARE] = make_hardware(buf.machine);
+ if (!uname_fields[UN_HARDWARE])
+ goto end;
+ break;
+#if NOT_IMPLEMENTED_OS
+ case 'o':
+ break;
+#endif
+ case 'h':
+ usage(stdout, argv[0]);
+ ec = 0;
+ goto end;
+ break;
+ default:
+ usage(stderr, argv[0]);
+ goto end;
+ break;
+ }
+ }
+
+ for (nr_pr = 0, i = UN_SYSNAME; i < UN_NR_FIELDS; i++) {
+ if (!uname_fields[i])
+ continue;
+ if (nr_pr)
+ fputc(' ', stdout);
+ fputs(uname_fields[i], stdout);
+ nr_pr++;
+ }
+ fputc('\n', stdout);
+
+ ec = 0;
+
+end:
+ if (uname_fields[UN_HARDWARE])
+ free(uname_fields[UN_HARDWARE]);
+ return ec;
+}