Import klibc_2.0.4.orig.tar.gz
authormaximilian attems <maks@debian.org>
Thu, 11 Sep 2014 19:23:25 +0000 (20:23 +0100)
committermaximilian attems <maks@debian.org>
Thu, 11 Sep 2014 19:23:25 +0000 (20:23 +0100)
[dgit import orig klibc_2.0.4.orig.tar.gz]

904 files changed:
.gitignore [new file with mode: 0644]
Kbuild [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
contrib/klibc.m4 [new file with mode: 0644]
defconfig [new file with mode: 0644]
git-rm-for-kernel.sh [new file with mode: 0755]
klcc/.gitignore [new file with mode: 0644]
klcc/Kbuild [new file with mode: 0644]
klcc/klcc.1 [new file with mode: 0644]
klcc/klcc.in [new file with mode: 0644]
klcc/makeklcc.pl [new file with mode: 0644]
klibc.spec.in [new file with mode: 0644]
makerpm.sh [new file with mode: 0755]
maketar.sh [new file with mode: 0755]
scripts/Kbuild.include [new file with mode: 0644]
scripts/Kbuild.install [new file with mode: 0644]
scripts/Kbuild.klibc [new file with mode: 0644]
scripts/Makefile.clean [new file with mode: 0644]
scripts/Makefile.host [new file with mode: 0644]
scripts/basic/.gitignore [new file with mode: 0644]
scripts/basic/Kbuild [new file with mode: 0644]
scripts/basic/fixdep.c [new file with mode: 0644]
usr/.gitignore [new file with mode: 0644]
usr/Kbuild [new file with mode: 0644]
usr/dash/.gitignore [new file with mode: 0644]
usr/dash/Kbuild [new file with mode: 0644]
usr/dash/README.dash [new file with mode: 0644]
usr/dash/TOUR [new file with mode: 0644]
usr/dash/alias.c [new file with mode: 0644]
usr/dash/alias.h [new file with mode: 0644]
usr/dash/arith_yacc.c [new file with mode: 0644]
usr/dash/arith_yacc.h [new file with mode: 0644]
usr/dash/arith_yylex.c [new file with mode: 0644]
usr/dash/bltin/bltin.h [new file with mode: 0644]
usr/dash/bltin/echo.1 [new file with mode: 0644]
usr/dash/bltin/printf.1 [new file with mode: 0644]
usr/dash/bltin/printf.c [new file with mode: 0644]
usr/dash/bltin/test.1 [new file with mode: 0644]
usr/dash/bltin/test.c [new file with mode: 0644]
usr/dash/builtins.def.in [new file with mode: 0644]
usr/dash/cd.c [new file with mode: 0644]
usr/dash/cd.h [new file with mode: 0644]
usr/dash/config.h [new file with mode: 0644]
usr/dash/error.c [new file with mode: 0644]
usr/dash/error.h [new file with mode: 0644]
usr/dash/eval.c [new file with mode: 0644]
usr/dash/eval.h [new file with mode: 0644]
usr/dash/exec.c [new file with mode: 0644]
usr/dash/exec.h [new file with mode: 0644]
usr/dash/expand.c [new file with mode: 0644]
usr/dash/expand.h [new file with mode: 0644]
usr/dash/funcs/cmv [new file with mode: 0644]
usr/dash/funcs/dirs [new file with mode: 0644]
usr/dash/funcs/kill [new file with mode: 0644]
usr/dash/funcs/login [new file with mode: 0644]
usr/dash/funcs/newgrp [new file with mode: 0644]
usr/dash/funcs/popd [new file with mode: 0644]
usr/dash/funcs/pushd [new file with mode: 0644]
usr/dash/funcs/suspend [new file with mode: 0644]
usr/dash/gendeps.pl [new file with mode: 0755]
usr/dash/hetio.c [new file with mode: 0644]
usr/dash/hetio.h [new file with mode: 0644]
usr/dash/histedit.c [new file with mode: 0644]
usr/dash/init.h [new file with mode: 0644]
usr/dash/input.c [new file with mode: 0644]
usr/dash/input.h [new file with mode: 0644]
usr/dash/jobs.c [new file with mode: 0644]
usr/dash/jobs.h [new file with mode: 0644]
usr/dash/machdep.h [new file with mode: 0644]
usr/dash/mail.c [new file with mode: 0644]
usr/dash/mail.h [new file with mode: 0644]
usr/dash/main.c [new file with mode: 0644]
usr/dash/main.h [new file with mode: 0644]
usr/dash/memalloc.c [new file with mode: 0644]
usr/dash/memalloc.h [new file with mode: 0644]
usr/dash/miscbltin.c [new file with mode: 0644]
usr/dash/miscbltin.h [new file with mode: 0644]
usr/dash/mkbuiltins [new file with mode: 0644]
usr/dash/mkinit.c [new file with mode: 0644]
usr/dash/mknodes.c [new file with mode: 0644]
usr/dash/mksyntax.c [new file with mode: 0644]
usr/dash/mktokens [new file with mode: 0644]
usr/dash/myhistedit.h [new file with mode: 0644]
usr/dash/mystring.c [new file with mode: 0644]
usr/dash/mystring.h [new file with mode: 0644]
usr/dash/nodes.c.pat [new file with mode: 0644]
usr/dash/nodetypes [new file with mode: 0644]
usr/dash/options.c [new file with mode: 0644]
usr/dash/options.h [new file with mode: 0644]
usr/dash/output.c [new file with mode: 0644]
usr/dash/output.h [new file with mode: 0644]
usr/dash/parser.c [new file with mode: 0644]
usr/dash/parser.h [new file with mode: 0644]
usr/dash/redir.c [new file with mode: 0644]
usr/dash/redir.h [new file with mode: 0644]
usr/dash/sh.1 [new file with mode: 0644]
usr/dash/shell.h [new file with mode: 0644]
usr/dash/show.c [new file with mode: 0644]
usr/dash/show.h [new file with mode: 0644]
usr/dash/system.c [new file with mode: 0644]
usr/dash/system.h [new file with mode: 0644]
usr/dash/trap.c [new file with mode: 0644]
usr/dash/trap.h [new file with mode: 0644]
usr/dash/var.c [new file with mode: 0644]
usr/dash/var.h [new file with mode: 0644]
usr/gzip/.gitignore [new file with mode: 0644]
usr/gzip/COPYING [new file with mode: 0644]
usr/gzip/Kbuild [new file with mode: 0644]
usr/gzip/README [new file with mode: 0644]
usr/gzip/bits.c [new file with mode: 0644]
usr/gzip/deflate.c [new file with mode: 0644]
usr/gzip/gzip.c [new file with mode: 0644]
usr/gzip/gzip.h [new file with mode: 0644]
usr/gzip/inflate.c [new file with mode: 0644]
usr/gzip/revision.h [new file with mode: 0644]
usr/gzip/tailor.h [new file with mode: 0644]
usr/gzip/trees.c [new file with mode: 0644]
usr/gzip/unzip.c [new file with mode: 0644]
usr/gzip/util.c [new file with mode: 0644]
usr/gzip/zip.c [new file with mode: 0644]
usr/include/Kbuild [new file with mode: 0644]
usr/include/alloca.h [new file with mode: 0644]
usr/include/arch/alpha/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/alpha/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/alpha/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/alpha/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/alpha/machine/asm.h [new file with mode: 0644]
usr/include/arch/arm/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/arm/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/arm/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/arm/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/arm/klibc/asmmacros.h [new file with mode: 0644]
usr/include/arch/arm64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/arm64/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/arm64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/arm64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/cris/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/cris/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/cris/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/cris/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/i386/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/i386/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/i386/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/i386/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/i386/klibc/diverr.h [new file with mode: 0644]
usr/include/arch/i386/sys/io.h [new file with mode: 0644]
usr/include/arch/i386/sys/vm86.h [new file with mode: 0644]
usr/include/arch/ia64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/ia64/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/ia64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/ia64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/m32r/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/m32r/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/m32r/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/m32r/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/m68k/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/m68k/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/m68k/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/m68k/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archfcntl.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archsocket.h [new file with mode: 0644]
usr/include/arch/mips/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/mips/machine/asm.h [new file with mode: 0644]
usr/include/arch/mips/sgidefs.h [new file with mode: 0644]
usr/include/arch/mips/spaces.h [new file with mode: 0644]
usr/include/arch/mips64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/mips64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/mips64/klibc/archsocket.h [new file with mode: 0644]
usr/include/arch/mips64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/parisc/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/parisc/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/parisc/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/parisc/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/ppc/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/ppc/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/ppc/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/ppc/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/ppc64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/ppc64/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/ppc64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/ppc64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/s390/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/s390/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/s390/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/s390/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/sh/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/sh/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/sh/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/sh/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/sparc/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/sparc/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/sparc/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/sparc/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/sparc/machine/asm.h [new file with mode: 0644]
usr/include/arch/sparc/machine/frame.h [new file with mode: 0644]
usr/include/arch/sparc/machine/trap.h [new file with mode: 0644]
usr/include/arch/sparc64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/sparc64/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/sparc64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/sparc64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/x86_64/klibc/archconfig.h [new file with mode: 0644]
usr/include/arch/x86_64/klibc/archsetjmp.h [new file with mode: 0644]
usr/include/arch/x86_64/klibc/archsignal.h [new file with mode: 0644]
usr/include/arch/x86_64/klibc/archstat.h [new file with mode: 0644]
usr/include/arch/x86_64/sys/io.h [new file with mode: 0644]
usr/include/arpa/inet.h [new file with mode: 0644]
usr/include/assert.h [new file with mode: 0644]
usr/include/bits32/bitsize.h [new file with mode: 0644]
usr/include/bits32/bitsize/limits.h [new file with mode: 0644]
usr/include/bits32/bitsize/stdint.h [new file with mode: 0644]
usr/include/bits32/bitsize/stdintconst.h [new file with mode: 0644]
usr/include/bits32/bitsize/stdintlimits.h [new file with mode: 0644]
usr/include/bits64/bitsize.h [new file with mode: 0644]
usr/include/bits64/bitsize/limits.h [new file with mode: 0644]
usr/include/bits64/bitsize/stdint.h [new file with mode: 0644]
usr/include/bits64/bitsize/stdintconst.h [new file with mode: 0644]
usr/include/bits64/bitsize/stdintlimits.h [new file with mode: 0644]
usr/include/byteswap.h [new file with mode: 0644]
usr/include/ctype.h [new file with mode: 0644]
usr/include/dirent.h [new file with mode: 0644]
usr/include/elf.h [new file with mode: 0644]
usr/include/endian.h [new file with mode: 0644]
usr/include/errno.h [new file with mode: 0644]
usr/include/fcntl.h [new file with mode: 0644]
usr/include/fnmatch.h [new file with mode: 0644]
usr/include/getopt.h [new file with mode: 0644]
usr/include/grp.h [new file with mode: 0644]
usr/include/inttypes.h [new file with mode: 0644]
usr/include/klibc/compiler.h [new file with mode: 0644]
usr/include/klibc/diverr.h [new file with mode: 0644]
usr/include/klibc/endian.h [new file with mode: 0644]
usr/include/klibc/extern.h [new file with mode: 0644]
usr/include/klibc/seek.h [new file with mode: 0644]
usr/include/klibc/stathelp.h [new file with mode: 0644]
usr/include/klibc/sysconfig.h [new file with mode: 0644]
usr/include/limits.h [new file with mode: 0644]
usr/include/malloc.h [new file with mode: 0644]
usr/include/mntent.h [new file with mode: 0644]
usr/include/net/if.h [new file with mode: 0644]
usr/include/net/if_arp.h [new file with mode: 0644]
usr/include/net/if_packet.h [new file with mode: 0644]
usr/include/net/route.h [new file with mode: 0644]
usr/include/netinet/if_ether.h [new file with mode: 0644]
usr/include/netinet/in.h [new file with mode: 0644]
usr/include/netinet/in6.h [new file with mode: 0644]
usr/include/netinet/ip.h [new file with mode: 0644]
usr/include/netinet/tcp.h [new file with mode: 0644]
usr/include/netinet/udp.h [new file with mode: 0644]
usr/include/netpacket/packet.h [new file with mode: 0644]
usr/include/paths.h [new file with mode: 0644]
usr/include/poll.h [new file with mode: 0644]
usr/include/pwd.h [new file with mode: 0644]
usr/include/sched.h [new file with mode: 0644]
usr/include/setjmp.h [new file with mode: 0644]
usr/include/signal.h [new file with mode: 0644]
usr/include/stdarg.h [new file with mode: 0644]
usr/include/stddef.h [new file with mode: 0644]
usr/include/stdint.h [new file with mode: 0644]
usr/include/stdio.h [new file with mode: 0644]
usr/include/stdlib.h [new file with mode: 0644]
usr/include/string.h [new file with mode: 0644]
usr/include/sys/auxv.h [new file with mode: 0644]
usr/include/sys/capability.h [new file with mode: 0644]
usr/include/sys/dirent.h [new file with mode: 0644]
usr/include/sys/elf32.h [new file with mode: 0644]
usr/include/sys/elf64.h [new file with mode: 0644]
usr/include/sys/elfcommon.h [new file with mode: 0644]
usr/include/sys/file.h [new file with mode: 0644]
usr/include/sys/fsuid.h [new file with mode: 0644]
usr/include/sys/inotify.h [new file with mode: 0644]
usr/include/sys/ioctl.h [new file with mode: 0644]
usr/include/sys/klog.h [new file with mode: 0644]
usr/include/sys/md.h [new file with mode: 0644]
usr/include/sys/mman.h [new file with mode: 0644]
usr/include/sys/mount.h [new file with mode: 0644]
usr/include/sys/param.h [new file with mode: 0644]
usr/include/sys/poll.h [new file with mode: 0644]
usr/include/sys/prctl.h [new file with mode: 0644]
usr/include/sys/reboot.h [new file with mode: 0644]
usr/include/sys/resource.h [new file with mode: 0644]
usr/include/sys/select.h [new file with mode: 0644]
usr/include/sys/sendfile.h [new file with mode: 0644]
usr/include/sys/socket.h [new file with mode: 0644]
usr/include/sys/socketcalls.h [new file with mode: 0644]
usr/include/sys/splice.h [new file with mode: 0644]
usr/include/sys/stat.h [new file with mode: 0644]
usr/include/sys/statfs.h [new file with mode: 0644]
usr/include/sys/syscall.h [new file with mode: 0644]
usr/include/sys/sysinfo.h [new file with mode: 0644]
usr/include/sys/sysmacros.h [new file with mode: 0644]
usr/include/sys/time.h [new file with mode: 0644]
usr/include/sys/times.h [new file with mode: 0644]
usr/include/sys/types.h [new file with mode: 0644]
usr/include/sys/uio.h [new file with mode: 0644]
usr/include/sys/un.h [new file with mode: 0644]
usr/include/sys/utime.h [new file with mode: 0644]
usr/include/sys/utsname.h [new file with mode: 0644]
usr/include/sys/vfs.h [new file with mode: 0644]
usr/include/sys/wait.h [new file with mode: 0644]
usr/include/sysexits.h [new file with mode: 0644]
usr/include/syslog.h [new file with mode: 0644]
usr/include/termios.h [new file with mode: 0644]
usr/include/time.h [new file with mode: 0644]
usr/include/unistd.h [new file with mode: 0644]
usr/include/utime.h [new file with mode: 0644]
usr/include/zconf.h [new file with mode: 0644]
usr/include/zlib.h [new file with mode: 0644]
usr/kinit/.gitignore [new file with mode: 0644]
usr/kinit/Kbuild [new file with mode: 0644]
usr/kinit/README [new file with mode: 0644]
usr/kinit/capabilities.c [new file with mode: 0644]
usr/kinit/capabilities.h [new file with mode: 0644]
usr/kinit/devname.c [new file with mode: 0644]
usr/kinit/do_mounts.c [new file with mode: 0644]
usr/kinit/do_mounts.h [new file with mode: 0644]
usr/kinit/do_mounts_md.c [new file with mode: 0644]
usr/kinit/do_mounts_mtd.c [new file with mode: 0644]
usr/kinit/fstype/Kbuild [new file with mode: 0644]
usr/kinit/fstype/btrfs.h [new file with mode: 0644]
usr/kinit/fstype/cramfs_fs.h [new file with mode: 0644]
usr/kinit/fstype/ext2_fs.h [new file with mode: 0644]
usr/kinit/fstype/ext3_fs.h [new file with mode: 0644]
usr/kinit/fstype/fstype.c [new file with mode: 0644]
usr/kinit/fstype/fstype.h [new file with mode: 0644]
usr/kinit/fstype/gfs2_fs.h [new file with mode: 0644]
usr/kinit/fstype/iso9660_sb.h [new file with mode: 0644]
usr/kinit/fstype/jfs_superblock.h [new file with mode: 0644]
usr/kinit/fstype/luks_fs.h [new file with mode: 0644]
usr/kinit/fstype/lvm2_sb.h [new file with mode: 0644]
usr/kinit/fstype/main.c [new file with mode: 0644]
usr/kinit/fstype/minix_fs.h [new file with mode: 0644]
usr/kinit/fstype/nilfs_fs.h [new file with mode: 0644]
usr/kinit/fstype/ocfs2_fs.h [new file with mode: 0644]
usr/kinit/fstype/reiser4_fs.h [new file with mode: 0644]
usr/kinit/fstype/reiserfs_fs.h [new file with mode: 0644]
usr/kinit/fstype/romfs_fs.h [new file with mode: 0644]
usr/kinit/fstype/squashfs_fs.h [new file with mode: 0644]
usr/kinit/fstype/swap_fs.h [new file with mode: 0644]
usr/kinit/fstype/xfs_sb.h [new file with mode: 0644]
usr/kinit/getarg.c [new file with mode: 0644]
usr/kinit/getintfile.c [new file with mode: 0644]
usr/kinit/initrd.c [new file with mode: 0644]
usr/kinit/ipconfig/Kbuild [new file with mode: 0644]
usr/kinit/ipconfig/README.ipconfig [new file with mode: 0644]
usr/kinit/ipconfig/bootp_packet.h [new file with mode: 0644]
usr/kinit/ipconfig/bootp_proto.c [new file with mode: 0644]
usr/kinit/ipconfig/bootp_proto.h [new file with mode: 0644]
usr/kinit/ipconfig/dhcp_proto.c [new file with mode: 0644]
usr/kinit/ipconfig/dhcp_proto.h [new file with mode: 0644]
usr/kinit/ipconfig/ipconfig.h [new file with mode: 0644]
usr/kinit/ipconfig/main.c [new file with mode: 0644]
usr/kinit/ipconfig/netdev.c [new file with mode: 0644]
usr/kinit/ipconfig/netdev.h [new file with mode: 0644]
usr/kinit/ipconfig/packet.c [new file with mode: 0644]
usr/kinit/ipconfig/packet.h [new file with mode: 0644]
usr/kinit/kinit.c [new file with mode: 0644]
usr/kinit/kinit.h [new file with mode: 0644]
usr/kinit/name_to_dev.c [new file with mode: 0644]
usr/kinit/nfsmount/Kbuild [new file with mode: 0644]
usr/kinit/nfsmount/README.locking [new file with mode: 0644]
usr/kinit/nfsmount/dummypmap.c [new file with mode: 0644]
usr/kinit/nfsmount/dummypmap.h [new file with mode: 0644]
usr/kinit/nfsmount/dummypmap_test.c [new file with mode: 0644]
usr/kinit/nfsmount/main.c [new file with mode: 0644]
usr/kinit/nfsmount/mount.c [new file with mode: 0644]
usr/kinit/nfsmount/nfsmount.h [new file with mode: 0644]
usr/kinit/nfsmount/portmap.c [new file with mode: 0644]
usr/kinit/nfsmount/sunrpc.c [new file with mode: 0644]
usr/kinit/nfsmount/sunrpc.h [new file with mode: 0644]
usr/kinit/nfsroot.c [new file with mode: 0644]
usr/kinit/ramdisk_load.c [new file with mode: 0644]
usr/kinit/readfile.c [new file with mode: 0644]
usr/kinit/resume/Kbuild [new file with mode: 0644]
usr/kinit/resume/resume.c [new file with mode: 0644]
usr/kinit/resume/resume.h [new file with mode: 0644]
usr/kinit/resume/resumelib.c [new file with mode: 0644]
usr/kinit/run-init/Kbuild [new file with mode: 0644]
usr/kinit/run-init/run-init.c [new file with mode: 0644]
usr/kinit/run-init/run-init.h [new file with mode: 0644]
usr/kinit/run-init/runinitlib.c [new file with mode: 0644]
usr/kinit/xpio.c [new file with mode: 0644]
usr/kinit/xpio.h [new file with mode: 0644]
usr/klibc/.gitignore [new file with mode: 0644]
usr/klibc/CAVEATS [new file with mode: 0644]
usr/klibc/Kbuild [new file with mode: 0644]
usr/klibc/LICENSE [new file with mode: 0644]
usr/klibc/README.klibc [new file with mode: 0644]
usr/klibc/SOCKETCALLS.def [new file with mode: 0644]
usr/klibc/SYSCALLS.def [new file with mode: 0644]
usr/klibc/__put_env.c [new file with mode: 0644]
usr/klibc/__shared_init.c [new file with mode: 0644]
usr/klibc/__signal.c [new file with mode: 0644]
usr/klibc/__static_init.c [new file with mode: 0644]
usr/klibc/abort.c [new file with mode: 0644]
usr/klibc/access.c [new file with mode: 0644]
usr/klibc/alarm.c [new file with mode: 0644]
usr/klibc/alphasort.c [new file with mode: 0644]
usr/klibc/arch/README.klibc.arch [new file with mode: 0644]
usr/klibc/arch/alpha/Kbuild [new file with mode: 0644]
usr/klibc/arch/alpha/MCONFIG [new file with mode: 0644]
usr/klibc/arch/alpha/README-gcc [new file with mode: 0644]
usr/klibc/arch/alpha/crt0.S [new file with mode: 0644]
usr/klibc/arch/alpha/divide.c [new file with mode: 0644]
usr/klibc/arch/alpha/pipe.S [new file with mode: 0644]
usr/klibc/arch/alpha/setjmp.S [new file with mode: 0644]
usr/klibc/arch/alpha/syscall.S [new file with mode: 0644]
usr/klibc/arch/alpha/sysdual.S [new file with mode: 0644]
usr/klibc/arch/alpha/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/arm/Kbuild [new file with mode: 0644]
usr/klibc/arch/arm/MCONFIG [new file with mode: 0644]
usr/klibc/arch/arm/__muldi3.c [new file with mode: 0644]
usr/klibc/arch/arm/aeabi_nonsense.S [new file with mode: 0644]
usr/klibc/arch/arm/crt0.S [new file with mode: 0644]
usr/klibc/arch/arm/setjmp.S [new file with mode: 0644]
usr/klibc/arch/arm/syscall.S [new file with mode: 0644]
usr/klibc/arch/arm/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/arm/vfork.S [new file with mode: 0644]
usr/klibc/arch/arm64/Kbuild [new file with mode: 0644]
usr/klibc/arch/arm64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/arm64/crt0.S [new file with mode: 0644]
usr/klibc/arch/arm64/setjmp.S [new file with mode: 0644]
usr/klibc/arch/arm64/syscall.S [new file with mode: 0644]
usr/klibc/arch/arm64/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/arm64/vfork.S [new file with mode: 0644]
usr/klibc/arch/cris/Kbuild [new file with mode: 0644]
usr/klibc/arch/cris/MCONFIG [new file with mode: 0644]
usr/klibc/arch/cris/__negdi2.S [new file with mode: 0644]
usr/klibc/arch/cris/crt0.S [new file with mode: 0644]
usr/klibc/arch/cris/divide.c [new file with mode: 0644]
usr/klibc/arch/cris/setjmp.S [new file with mode: 0644]
usr/klibc/arch/cris/syscall.S [new file with mode: 0644]
usr/klibc/arch/cris/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/cris/vfork.S [new file with mode: 0644]
usr/klibc/arch/i386/Kbuild [new file with mode: 0644]
usr/klibc/arch/i386/MCONFIG [new file with mode: 0644]
usr/klibc/arch/i386/archinit.c [new file with mode: 0644]
usr/klibc/arch/i386/crt0.S [new file with mode: 0644]
usr/klibc/arch/i386/libgcc/__ashldi3.S [new file with mode: 0644]
usr/klibc/arch/i386/libgcc/__ashrdi3.S [new file with mode: 0644]
usr/klibc/arch/i386/libgcc/__lshrdi3.S [new file with mode: 0644]
usr/klibc/arch/i386/libgcc/__muldi3.S [new file with mode: 0644]
usr/klibc/arch/i386/libgcc/__negdi2.S [new file with mode: 0644]
usr/klibc/arch/i386/open.S [new file with mode: 0644]
usr/klibc/arch/i386/openat.S [new file with mode: 0644]
usr/klibc/arch/i386/setjmp.S [new file with mode: 0644]
usr/klibc/arch/i386/socketcall.S [new file with mode: 0644]
usr/klibc/arch/i386/syscall.S [new file with mode: 0644]
usr/klibc/arch/i386/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/i386/varsyscall.S [new file with mode: 0644]
usr/klibc/arch/i386/vfork.S [new file with mode: 0644]
usr/klibc/arch/ia64/Kbuild [new file with mode: 0644]
usr/klibc/arch/ia64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/ia64/crt0.S [new file with mode: 0644]
usr/klibc/arch/ia64/pipe.S [new file with mode: 0644]
usr/klibc/arch/ia64/setjmp.S [new file with mode: 0644]
usr/klibc/arch/ia64/syscall.S [new file with mode: 0644]
usr/klibc/arch/ia64/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/ia64/vfork.S [new file with mode: 0644]
usr/klibc/arch/m32r/Kbuild [new file with mode: 0644]
usr/klibc/arch/m32r/MCONFIG [new file with mode: 0644]
usr/klibc/arch/m32r/crt0.S [new file with mode: 0644]
usr/klibc/arch/m32r/setjmp.S [new file with mode: 0644]
usr/klibc/arch/m32r/syscall.S [new file with mode: 0644]
usr/klibc/arch/m32r/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/m68k/Kbuild [new file with mode: 0644]
usr/klibc/arch/m68k/MCONFIG [new file with mode: 0644]
usr/klibc/arch/m68k/crt0.S [new file with mode: 0644]
usr/klibc/arch/m68k/open.S [new file with mode: 0644]
usr/klibc/arch/m68k/openat.S [new file with mode: 0644]
usr/klibc/arch/m68k/setjmp.S [new file with mode: 0644]
usr/klibc/arch/m68k/syscall.S [new file with mode: 0644]
usr/klibc/arch/m68k/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/m68k/vfork.S [new file with mode: 0644]
usr/klibc/arch/mips/Kbuild [new file with mode: 0644]
usr/klibc/arch/mips/MCONFIG [new file with mode: 0644]
usr/klibc/arch/mips/crt0.S [new file with mode: 0644]
usr/klibc/arch/mips/klibc.ld [new file with mode: 0644]
usr/klibc/arch/mips/pipe.S [new file with mode: 0644]
usr/klibc/arch/mips/setjmp.S [new file with mode: 0644]
usr/klibc/arch/mips/syscall.S [new file with mode: 0644]
usr/klibc/arch/mips/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/mips/vfork.S [new file with mode: 0644]
usr/klibc/arch/mips64/Kbuild [new file with mode: 0644]
usr/klibc/arch/mips64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/parisc/Kbuild [new file with mode: 0644]
usr/klibc/arch/parisc/MCONFIG [new file with mode: 0644]
usr/klibc/arch/parisc/crt0.S [new file with mode: 0644]
usr/klibc/arch/parisc/setjmp.S [new file with mode: 0644]
usr/klibc/arch/parisc/syscall.S [new file with mode: 0644]
usr/klibc/arch/parisc/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/parisc/vfork.S [new file with mode: 0644]
usr/klibc/arch/ppc/Kbuild [new file with mode: 0644]
usr/klibc/arch/ppc/MCONFIG [new file with mode: 0644]
usr/klibc/arch/ppc/crt0.S [new file with mode: 0644]
usr/klibc/arch/ppc/setjmp.S [new file with mode: 0644]
usr/klibc/arch/ppc/syscall.S [new file with mode: 0644]
usr/klibc/arch/ppc/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/ppc64/Kbuild [new file with mode: 0644]
usr/klibc/arch/ppc64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/ppc64/crt0.S [new file with mode: 0644]
usr/klibc/arch/ppc64/setjmp.S [new file with mode: 0644]
usr/klibc/arch/ppc64/syscall.c [new file with mode: 0644]
usr/klibc/arch/ppc64/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/s390/Kbuild [new file with mode: 0644]
usr/klibc/arch/s390/MCONFIG [new file with mode: 0644]
usr/klibc/arch/s390/crt0.S [new file with mode: 0644]
usr/klibc/arch/s390/mmap.c [new file with mode: 0644]
usr/klibc/arch/s390/setjmp.S [new file with mode: 0644]
usr/klibc/arch/s390/syscall.c [new file with mode: 0644]
usr/klibc/arch/s390/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/sh/Kbuild [new file with mode: 0644]
usr/klibc/arch/sh/MCONFIG [new file with mode: 0644]
usr/klibc/arch/sh/crt0.S [new file with mode: 0644]
usr/klibc/arch/sh/pipe.S [new file with mode: 0644]
usr/klibc/arch/sh/setjmp.S [new file with mode: 0644]
usr/klibc/arch/sh/syscall.S [new file with mode: 0644]
usr/klibc/arch/sh/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/sparc/Kbuild [new file with mode: 0644]
usr/klibc/arch/sparc/MCONFIG [new file with mode: 0644]
usr/klibc/arch/sparc/__muldi3.S [new file with mode: 0644]
usr/klibc/arch/sparc/crt0.S [new file with mode: 0644]
usr/klibc/arch/sparc/crt0i.S [new file with mode: 0644]
usr/klibc/arch/sparc/divrem.m4 [new file with mode: 0644]
usr/klibc/arch/sparc/pipe.S [new file with mode: 0644]
usr/klibc/arch/sparc/setjmp.S [new file with mode: 0644]
usr/klibc/arch/sparc/smul.S [new file with mode: 0644]
usr/klibc/arch/sparc/syscall.S [new file with mode: 0644]
usr/klibc/arch/sparc/sysfork.S [new file with mode: 0644]
usr/klibc/arch/sparc/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/sparc/umul.S [new file with mode: 0644]
usr/klibc/arch/sparc64/Kbuild [new file with mode: 0644]
usr/klibc/arch/sparc64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/sparc64/crt0.S [new file with mode: 0644]
usr/klibc/arch/sparc64/pipe.S [new file with mode: 0644]
usr/klibc/arch/sparc64/setjmp.S [new file with mode: 0644]
usr/klibc/arch/sparc64/syscall.S [new file with mode: 0644]
usr/klibc/arch/sparc64/sysfork.S [new file with mode: 0644]
usr/klibc/arch/sparc64/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/x86_64/Kbuild [new file with mode: 0644]
usr/klibc/arch/x86_64/MCONFIG [new file with mode: 0644]
usr/klibc/arch/x86_64/crt0.S [new file with mode: 0644]
usr/klibc/arch/x86_64/setjmp.S [new file with mode: 0644]
usr/klibc/arch/x86_64/sigreturn.S [new file with mode: 0644]
usr/klibc/arch/x86_64/syscall.S [new file with mode: 0644]
usr/klibc/arch/x86_64/sysstub.ph [new file with mode: 0644]
usr/klibc/arch/x86_64/vfork.S [new file with mode: 0644]
usr/klibc/asprintf.c [new file with mode: 0644]
usr/klibc/assert.c [new file with mode: 0644]
usr/klibc/atexit.c [new file with mode: 0644]
usr/klibc/atexit.h [new file with mode: 0644]
usr/klibc/atoi.c [new file with mode: 0644]
usr/klibc/atol.c [new file with mode: 0644]
usr/klibc/atoll.c [new file with mode: 0644]
usr/klibc/atox.c [new file with mode: 0644]
usr/klibc/brk.c [new file with mode: 0644]
usr/klibc/bsd_signal.c [new file with mode: 0644]
usr/klibc/bsearch.c [new file with mode: 0644]
usr/klibc/bzero.c [new file with mode: 0644]
usr/klibc/calloc.c [new file with mode: 0644]
usr/klibc/chmod.c [new file with mode: 0644]
usr/klibc/chown.c [new file with mode: 0644]
usr/klibc/clearenv.c [new file with mode: 0644]
usr/klibc/closelog.c [new file with mode: 0644]
usr/klibc/creat.c [new file with mode: 0644]
usr/klibc/ctype/ctypefunc.h [new file with mode: 0644]
usr/klibc/ctype/isalnum.c [new file with mode: 0644]
usr/klibc/ctype/isalpha.c [new file with mode: 0644]
usr/klibc/ctype/isascii.c [new file with mode: 0644]
usr/klibc/ctype/isblank.c [new file with mode: 0644]
usr/klibc/ctype/iscntrl.c [new file with mode: 0644]
usr/klibc/ctype/isdigit.c [new file with mode: 0644]
usr/klibc/ctype/isgraph.c [new file with mode: 0644]
usr/klibc/ctype/islower.c [new file with mode: 0644]
usr/klibc/ctype/isprint.c [new file with mode: 0644]
usr/klibc/ctype/ispunct.c [new file with mode: 0644]
usr/klibc/ctype/isspace.c [new file with mode: 0644]
usr/klibc/ctype/isupper.c [new file with mode: 0644]
usr/klibc/ctype/isxdigit.c [new file with mode: 0644]
usr/klibc/ctype/tolower.c [new file with mode: 0644]
usr/klibc/ctype/toupper.c [new file with mode: 0644]
usr/klibc/ctypes.c [new file with mode: 0644]
usr/klibc/daemon.c [new file with mode: 0644]
usr/klibc/dup2.c [new file with mode: 0644]
usr/klibc/endmntent.c [new file with mode: 0644]
usr/klibc/env.h [new file with mode: 0644]
usr/klibc/exec_l.c [new file with mode: 0644]
usr/klibc/execl.c [new file with mode: 0644]
usr/klibc/execle.c [new file with mode: 0644]
usr/klibc/execlp.c [new file with mode: 0644]
usr/klibc/execlpe.c [new file with mode: 0644]
usr/klibc/execv.c [new file with mode: 0644]
usr/klibc/execvp.c [new file with mode: 0644]
usr/klibc/execvpe.c [new file with mode: 0644]
usr/klibc/exit.c [new file with mode: 0644]
usr/klibc/fgets.c [new file with mode: 0644]
usr/klibc/fnmatch.c [new file with mode: 0644]
usr/klibc/fork.c [new file with mode: 0644]
usr/klibc/fprintf.c [new file with mode: 0644]
usr/klibc/fputc.c [new file with mode: 0644]
usr/klibc/fputs.c [new file with mode: 0644]
usr/klibc/fread2.c [new file with mode: 0644]
usr/klibc/fstatfs.c [new file with mode: 0644]
usr/klibc/fwrite2.c [new file with mode: 0644]
usr/klibc/getcwd.c [new file with mode: 0644]
usr/klibc/getdomainname.c [new file with mode: 0644]
usr/klibc/getenv.c [new file with mode: 0644]
usr/klibc/gethostname.c [new file with mode: 0644]
usr/klibc/getmntent.c [new file with mode: 0644]
usr/klibc/getopt.c [new file with mode: 0644]
usr/klibc/getopt_long.c [new file with mode: 0644]
usr/klibc/getpgrp.c [new file with mode: 0644]
usr/klibc/getpriority.c [new file with mode: 0644]
usr/klibc/getpt.c [new file with mode: 0644]
usr/klibc/globals.c [new file with mode: 0644]
usr/klibc/inet/bindresvport.c [new file with mode: 0644]
usr/klibc/inet/inet_addr.c [new file with mode: 0644]
usr/klibc/inet/inet_aton.c [new file with mode: 0644]
usr/klibc/inet/inet_ntoa.c [new file with mode: 0644]
usr/klibc/inet/inet_ntop.c [new file with mode: 0644]
usr/klibc/inet/inet_pton.c [new file with mode: 0644]
usr/klibc/interp.S [new file with mode: 0644]
usr/klibc/isatty.c [new file with mode: 0644]
usr/klibc/jrand48.c [new file with mode: 0644]
usr/klibc/lchown.c [new file with mode: 0644]
usr/klibc/libc_init.c [new file with mode: 0644]
usr/klibc/libgcc/__ashldi3.c [new file with mode: 0644]
usr/klibc/libgcc/__ashrdi3.c [new file with mode: 0644]
usr/klibc/libgcc/__clzsi2.c [new file with mode: 0644]
usr/klibc/libgcc/__divdi3.c [new file with mode: 0644]
usr/klibc/libgcc/__divsi3.c [new file with mode: 0644]
usr/klibc/libgcc/__lshrdi3.c [new file with mode: 0644]
usr/klibc/libgcc/__moddi3.c [new file with mode: 0644]
usr/klibc/libgcc/__modsi3.c [new file with mode: 0644]
usr/klibc/libgcc/__udivdi3.c [new file with mode: 0644]
usr/klibc/libgcc/__udivmoddi4.c [new file with mode: 0644]
usr/klibc/libgcc/__udivmodsi4.c [new file with mode: 0644]
usr/klibc/libgcc/__udivsi3.c [new file with mode: 0644]
usr/klibc/libgcc/__umoddi3.c [new file with mode: 0644]
usr/klibc/libgcc/__umodsi3.c [new file with mode: 0644]
usr/klibc/link.c [new file with mode: 0644]
usr/klibc/lrand48.c [new file with mode: 0644]
usr/klibc/lseek.c [new file with mode: 0644]
usr/klibc/lstat.c [new file with mode: 0644]
usr/klibc/makeerrlist.pl [new file with mode: 0644]
usr/klibc/malloc.c [new file with mode: 0644]
usr/klibc/malloc.h [new file with mode: 0644]
usr/klibc/memccpy.c [new file with mode: 0644]
usr/klibc/memchr.c [new file with mode: 0644]
usr/klibc/memcmp.c [new file with mode: 0644]
usr/klibc/memcpy.c [new file with mode: 0644]
usr/klibc/memmem.c [new file with mode: 0644]
usr/klibc/memmove.c [new file with mode: 0644]
usr/klibc/memrchr.c [new file with mode: 0644]
usr/klibc/memset.c [new file with mode: 0644]
usr/klibc/memswap.c [new file with mode: 0644]
usr/klibc/mkdir.c [new file with mode: 0644]
usr/klibc/mknod.c [new file with mode: 0644]
usr/klibc/mmap.c [new file with mode: 0644]
usr/klibc/mrand48.c [new file with mode: 0644]
usr/klibc/nice.c [new file with mode: 0644]
usr/klibc/nrand48.c [new file with mode: 0644]
usr/klibc/nullenv.c [new file with mode: 0644]
usr/klibc/onexit.c [new file with mode: 0644]
usr/klibc/open.c [new file with mode: 0644]
usr/klibc/open_cloexec.c [new file with mode: 0644]
usr/klibc/openat.c [new file with mode: 0644]
usr/klibc/pause.c [new file with mode: 0644]
usr/klibc/perror.c [new file with mode: 0644]
usr/klibc/pipe.c [new file with mode: 0644]
usr/klibc/poll.c [new file with mode: 0644]
usr/klibc/posix_openpt.c [new file with mode: 0644]
usr/klibc/ppoll.c [new file with mode: 0644]
usr/klibc/printf.c [new file with mode: 0644]
usr/klibc/pselect.c [new file with mode: 0644]
usr/klibc/pty.c [new file with mode: 0644]
usr/klibc/putchar.c [new file with mode: 0644]
usr/klibc/putenv.c [new file with mode: 0644]
usr/klibc/puts.c [new file with mode: 0644]
usr/klibc/qsort.c [new file with mode: 0644]
usr/klibc/raise.c [new file with mode: 0644]
usr/klibc/readdir.c [new file with mode: 0644]
usr/klibc/readlink.c [new file with mode: 0644]
usr/klibc/realloc.c [new file with mode: 0644]
usr/klibc/reboot.c [new file with mode: 0644]
usr/klibc/recv.c [new file with mode: 0644]
usr/klibc/remove.c [new file with mode: 0644]
usr/klibc/rename.c [new file with mode: 0644]
usr/klibc/rmdir.c [new file with mode: 0644]
usr/klibc/sbrk.c [new file with mode: 0644]
usr/klibc/scandir.c [new file with mode: 0644]
usr/klibc/seed48.c [new file with mode: 0644]
usr/klibc/select.c [new file with mode: 0644]
usr/klibc/send.c [new file with mode: 0644]
usr/klibc/setegid.c [new file with mode: 0644]
usr/klibc/setenv.c [new file with mode: 0644]
usr/klibc/seteuid.c [new file with mode: 0644]
usr/klibc/setmntent.c [new file with mode: 0644]
usr/klibc/setpgrp.c [new file with mode: 0644]
usr/klibc/sha1hash.c [new file with mode: 0644]
usr/klibc/shm_open.c [new file with mode: 0644]
usr/klibc/shm_unlink.c [new file with mode: 0644]
usr/klibc/sigabbrev.c [new file with mode: 0644]
usr/klibc/sigaction.c [new file with mode: 0644]
usr/klibc/siglist.c [new file with mode: 0644]
usr/klibc/siglongjmp.c [new file with mode: 0644]
usr/klibc/sigpending.c [new file with mode: 0644]
usr/klibc/sigprocmask.c [new file with mode: 0644]
usr/klibc/sigsuspend.c [new file with mode: 0644]
usr/klibc/sleep.c [new file with mode: 0644]
usr/klibc/snprintf.c [new file with mode: 0644]
usr/klibc/socketcalls.pl [new file with mode: 0644]
usr/klibc/socketcalls/.gitignore [new file with mode: 0644]
usr/klibc/socketcalls/Kbuild [new file with mode: 0644]
usr/klibc/socketcalls/socketcommon.h [new file with mode: 0644]
usr/klibc/sprintf.c [new file with mode: 0644]
usr/klibc/srand48.c [new file with mode: 0644]
usr/klibc/sscanf.c [new file with mode: 0644]
usr/klibc/stat.c [new file with mode: 0644]
usr/klibc/statfs.c [new file with mode: 0644]
usr/klibc/stdio/fclose.c [new file with mode: 0644]
usr/klibc/stdio/fdopen.c [new file with mode: 0644]
usr/klibc/stdio/feof.c [new file with mode: 0644]
usr/klibc/stdio/ferror.c [new file with mode: 0644]
usr/klibc/stdio/fflush.c [new file with mode: 0644]
usr/klibc/stdio/fgetc.c [new file with mode: 0644]
usr/klibc/stdio/fileno.c [new file with mode: 0644]
usr/klibc/stdio/fopen.c [new file with mode: 0644]
usr/klibc/stdio/fread.c [new file with mode: 0644]
usr/klibc/stdio/fseek.c [new file with mode: 0644]
usr/klibc/stdio/ftell.c [new file with mode: 0644]
usr/klibc/stdio/fwrite.c [new file with mode: 0644]
usr/klibc/stdio/rewind.c [new file with mode: 0644]
usr/klibc/stdio/stdioint.h [new file with mode: 0644]
usr/klibc/stdio/ungetc.c [new file with mode: 0644]
usr/klibc/strcasecmp.c [new file with mode: 0644]
usr/klibc/strcat.c [new file with mode: 0644]
usr/klibc/strchr.c [new file with mode: 0644]
usr/klibc/strcmp.c [new file with mode: 0644]
usr/klibc/strcpy.c [new file with mode: 0644]
usr/klibc/strcspn.c [new file with mode: 0644]
usr/klibc/strdup.c [new file with mode: 0644]
usr/klibc/strerror.c [new file with mode: 0644]
usr/klibc/strlcat.c [new file with mode: 0644]
usr/klibc/strlcpy.c [new file with mode: 0644]
usr/klibc/strlen.c [new file with mode: 0644]
usr/klibc/strncasecmp.c [new file with mode: 0644]
usr/klibc/strncat.c [new file with mode: 0644]
usr/klibc/strncmp.c [new file with mode: 0644]
usr/klibc/strncpy.c [new file with mode: 0644]
usr/klibc/strndup.c [new file with mode: 0644]
usr/klibc/strnlen.c [new file with mode: 0644]
usr/klibc/strntoimax.c [new file with mode: 0644]
usr/klibc/strntoumax.c [new file with mode: 0644]
usr/klibc/strpbrk.c [new file with mode: 0644]
usr/klibc/strrchr.c [new file with mode: 0644]
usr/klibc/strsep.c [new file with mode: 0644]
usr/klibc/strsignal.c [new file with mode: 0644]
usr/klibc/strspn.c [new file with mode: 0644]
usr/klibc/strstr.c [new file with mode: 0644]
usr/klibc/strtoimax.c [new file with mode: 0644]
usr/klibc/strtok.c [new file with mode: 0644]
usr/klibc/strtok_r.c [new file with mode: 0644]
usr/klibc/strtol.c [new file with mode: 0644]
usr/klibc/strtoll.c [new file with mode: 0644]
usr/klibc/strtotimespec.c [new file with mode: 0644]
usr/klibc/strtotimeval.c [new file with mode: 0644]
usr/klibc/strtotimex.c [new file with mode: 0644]
usr/klibc/strtoul.c [new file with mode: 0644]
usr/klibc/strtoull.c [new file with mode: 0644]
usr/klibc/strtoumax.c [new file with mode: 0644]
usr/klibc/strtox.c [new file with mode: 0644]
usr/klibc/strxspn.c [new file with mode: 0644]
usr/klibc/strxspn.h [new file with mode: 0644]
usr/klibc/symlink.c [new file with mode: 0644]
usr/klibc/syscalls.pl [new file with mode: 0644]
usr/klibc/syscalls/.gitignore [new file with mode: 0644]
usr/klibc/syscalls/Kbuild [new file with mode: 0644]
usr/klibc/syscalls/syscommon.h [new file with mode: 0644]
usr/klibc/syslog.c [new file with mode: 0644]
usr/klibc/system.c [new file with mode: 0644]
usr/klibc/sysv_signal.c [new file with mode: 0644]
usr/klibc/tests/Kbuild [new file with mode: 0644]
usr/klibc/tests/environ.c [new file with mode: 0644]
usr/klibc/tests/fcntl.c [new file with mode: 0644]
usr/klibc/tests/fnmatch.c [new file with mode: 0644]
usr/klibc/tests/getoptlong.c [new file with mode: 0644]
usr/klibc/tests/getopttest.c [new file with mode: 0644]
usr/klibc/tests/getpagesize.c [new file with mode: 0644]
usr/klibc/tests/hello.c [new file with mode: 0644]
usr/klibc/tests/idtest.c [new file with mode: 0644]
usr/klibc/tests/lseek.c [new file with mode: 0644]
usr/klibc/tests/malloctest.c [new file with mode: 0644]
usr/klibc/tests/malloctest2.c [new file with mode: 0644]
usr/klibc/tests/memstrtest.c [new file with mode: 0644]
usr/klibc/tests/microhello.c [new file with mode: 0644]
usr/klibc/tests/minihello.c [new file with mode: 0644]
usr/klibc/tests/mmaptest.c [new file with mode: 0644]
usr/klibc/tests/opentest.c [new file with mode: 0644]
usr/klibc/tests/pipetest.c [new file with mode: 0644]
usr/klibc/tests/rtsig.c [new file with mode: 0644]
usr/klibc/tests/select.c [new file with mode: 0644]
usr/klibc/tests/setenvtest.c [new file with mode: 0644]
usr/klibc/tests/setjmptest.c [new file with mode: 0644]
usr/klibc/tests/sig-nodefer.c [new file with mode: 0644]
usr/klibc/tests/sigint.c [new file with mode: 0644]
usr/klibc/tests/socket.c [new file with mode: 0644]
usr/klibc/tests/sscanf.c [new file with mode: 0644]
usr/klibc/tests/stat.c [new file with mode: 0644]
usr/klibc/tests/statfs.c [new file with mode: 0644]
usr/klibc/tests/stdio.c [new file with mode: 0644]
usr/klibc/tests/strlcpycat.c [new file with mode: 0644]
usr/klibc/tests/strtoimax.c [new file with mode: 0644]
usr/klibc/tests/strtotime.c [new file with mode: 0644]
usr/klibc/tests/testrand48.c [new file with mode: 0644]
usr/klibc/tests/testvsnp.c [new file with mode: 0644]
usr/klibc/tests/vfork.c [new file with mode: 0644]
usr/klibc/time.c [new file with mode: 0644]
usr/klibc/umount.c [new file with mode: 0644]
usr/klibc/unlink.c [new file with mode: 0644]
usr/klibc/unsetenv.c [new file with mode: 0644]
usr/klibc/userdb/getgrgid.c [new file with mode: 0644]
usr/klibc/userdb/getgrnam.c [new file with mode: 0644]
usr/klibc/userdb/getpwnam.c [new file with mode: 0644]
usr/klibc/userdb/getpwuid.c [new file with mode: 0644]
usr/klibc/userdb/root_group.c [new file with mode: 0644]
usr/klibc/userdb/root_user.c [new file with mode: 0644]
usr/klibc/userdb/userdb.h [new file with mode: 0644]
usr/klibc/usleep.c [new file with mode: 0644]
usr/klibc/utime.c [new file with mode: 0644]
usr/klibc/utimes.c [new file with mode: 0644]
usr/klibc/vasprintf.c [new file with mode: 0644]
usr/klibc/version [new file with mode: 0644]
usr/klibc/vfork.c [new file with mode: 0644]
usr/klibc/vfprintf.c [new file with mode: 0644]
usr/klibc/vprintf.c [new file with mode: 0644]
usr/klibc/vsnprintf.c [new file with mode: 0644]
usr/klibc/vsprintf.c [new file with mode: 0644]
usr/klibc/vsscanf.c [new file with mode: 0644]
usr/klibc/wait.c [new file with mode: 0644]
usr/klibc/wait3.c [new file with mode: 0644]
usr/klibc/waitpid.c [new file with mode: 0644]
usr/klibc/zalloc.c [new file with mode: 0644]
usr/klibc/zlib/FAQ [new file with mode: 0644]
usr/klibc/zlib/INDEX [new file with mode: 0644]
usr/klibc/zlib/Kbuild [new file with mode: 0644]
usr/klibc/zlib/README [new file with mode: 0644]
usr/klibc/zlib/adler32.c [new file with mode: 0644]
usr/klibc/zlib/algorithm.txt [new file with mode: 0644]
usr/klibc/zlib/compress.c [new file with mode: 0644]
usr/klibc/zlib/crc32.c [new file with mode: 0644]
usr/klibc/zlib/crc32.h [new file with mode: 0644]
usr/klibc/zlib/deflate.c [new file with mode: 0644]
usr/klibc/zlib/deflate.h [new file with mode: 0644]
usr/klibc/zlib/gzio.c [new file with mode: 0644]
usr/klibc/zlib/infback.c [new file with mode: 0644]
usr/klibc/zlib/inffast.c [new file with mode: 0644]
usr/klibc/zlib/inffast.h [new file with mode: 0644]
usr/klibc/zlib/inffixed.h [new file with mode: 0644]
usr/klibc/zlib/inflate.c [new file with mode: 0644]
usr/klibc/zlib/inflate.h [new file with mode: 0644]
usr/klibc/zlib/inftrees.c [new file with mode: 0644]
usr/klibc/zlib/inftrees.h [new file with mode: 0644]
usr/klibc/zlib/trees.c [new file with mode: 0644]
usr/klibc/zlib/trees.h [new file with mode: 0644]
usr/klibc/zlib/uncompr.c [new file with mode: 0644]
usr/klibc/zlib/zconf.in.h [new file with mode: 0644]
usr/klibc/zlib/zlib.3 [new file with mode: 0644]
usr/klibc/zlib/zutil.c [new file with mode: 0644]
usr/klibc/zlib/zutil.h [new file with mode: 0644]
usr/utils/Kbuild [new file with mode: 0644]
usr/utils/cat.c [new file with mode: 0644]
usr/utils/chroot.c [new file with mode: 0644]
usr/utils/cpio.c [new file with mode: 0644]
usr/utils/dd.c [new file with mode: 0644]
usr/utils/dmesg.c [new file with mode: 0644]
usr/utils/false.c [new file with mode: 0644]
usr/utils/file_mode.c [new file with mode: 0644]
usr/utils/file_mode.h [new file with mode: 0644]
usr/utils/halt.c [new file with mode: 0644]
usr/utils/kill.c [new file with mode: 0644]
usr/utils/ln.c [new file with mode: 0644]
usr/utils/loop.h [new file with mode: 0644]
usr/utils/losetup.c [new file with mode: 0644]
usr/utils/ls.c [new file with mode: 0644]
usr/utils/minips.c [new file with mode: 0644]
usr/utils/mkdir.c [new file with mode: 0644]
usr/utils/mkfifo.c [new file with mode: 0644]
usr/utils/mknod.c [new file with mode: 0644]
usr/utils/mount_main.c [new file with mode: 0644]
usr/utils/mount_opts.c [new file with mode: 0644]
usr/utils/mount_opts.h [new file with mode: 0644]
usr/utils/mv.c [new file with mode: 0644]
usr/utils/nuke.c [new file with mode: 0644]
usr/utils/pivot_root.c [new file with mode: 0644]
usr/utils/readlink.c [new file with mode: 0644]
usr/utils/sleep.c [new file with mode: 0644]
usr/utils/sync.c [new file with mode: 0644]
usr/utils/true.c [new file with mode: 0644]
usr/utils/umount.c [new file with mode: 0644]
usr/utils/uname.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..8a60b89
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# Normal rules
+#
+*.o
+*.o.cmd
+.*.cmd
+*.g
+\#*
+.\#*
+*~
+
+# Top-level ignorables
+/linux
+/.config
+
+# Common generated subdirectores
+shared
+static
diff --git a/Kbuild b/Kbuild
new file mode 100644 (file)
index 0000000..63f8f7d
--- /dev/null
+++ b/Kbuild
@@ -0,0 +1,18 @@
+#
+# Kbuild file for klibc
+#
+.PHONY: $(obj)/all
+always := all
+
+$(obj)/all:
+       $(Q)$(MAKE) $(klibc)=scripts/basic
+       $(Q)$(MAKE) $(klibc)=usr/klibc
+       $(Q)$(MAKE) $(klibc)=usr/kinit
+       $(Q)$(MAKE) $(klibc)=usr/dash
+       $(Q)$(MAKE) $(klibc)=usr/utils
+       $(Q)$(MAKE) $(klibc)=usr/gzip
+
+
+# Directories to visit during clean and install
+subdir- := scripts/basic klcc usr/klibc usr/dash usr/utils usr/gzip \
+          usr/kinit usr/klibc/tests
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..dc10fc5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,187 @@
+SRCROOT = .
+
+# *DOCUMENTATION*
+# To see a list of typical targets execute "make help"
+
+# kbuild compatibility
+export srctree  := $(shell pwd)
+export objtree  := $(shell pwd)
+export KLIBCSRC := usr/klibc
+export VERSION := $(shell cat $(srctree)/$(KLIBCSRC)/version)
+export KLIBCINC := usr/include
+export KLIBCOBJ := usr/klibc
+export KLIBCKERNELSRC ?= linux
+export KLIBCKERNELOBJ ?= $(KLIBCKERNELSRC)
+
+export VPATH := $(srctree)
+
+include $(srctree)/scripts/Kbuild.include
+
+KLIBCROSS      ?= $(CROSS_COMPILE)
+export KLIBCROSS
+export CC      := $(KLIBCROSS)gcc
+export LD      := $(KLIBCROSS)ld
+export AR      := $(KLIBCROSS)ar
+export RANLIB  := $(KLIBCROSS)ranlib
+export STRIP   := $(KLIBCROSS)strip
+export NM      := $(KLIBCROSS)nm
+export OBJCOPY  := $(KLIBCROSS)objcopy
+export OBJDUMP  := $(KLIBCROSS)objdump
+
+NOSTDINC_FLAGS := -nostdlib -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+
+ARCH             := $(shell uname -m | sed -e s/i.86/i386/ \
+                       -e s/parisc64/parisc/ -e s/sun4u/sparc64/ \
+                       -e s/arm.*/arm/ -e s/sa110/arm/ \
+                       -e s/aarch64.*/arm64/ -e s/sh.*/sh/ \
+                       -e s/ppc64le/ppc64/)
+export KLIBCARCH  ?= $(ARCH)
+export KLIBCARCHDIR := $(shell echo $(KLIBCARCH) | sed -e s/s390x/s390/)
+
+export HOSTCC     := gcc
+export HOSTCFLAGS := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+export PERL       := perl
+
+# Location for installation
+export prefix      = /usr
+export bindir      = $(prefix)/bin
+export libdir      = $(prefix)/lib
+export mandir      = $(prefix)/man
+export INSTALLDIR  = $(prefix)/lib/klibc
+export INSTALLROOT =
+
+# Create a fake .config as present in the kernel tree
+# But if it exists leave it alone
+$(if $(wildcard $(objtree)/.config),,\
+  $(shell cp $(srctree)/defconfig $(objtree)/.config))
+
+# Prefix Make commands with $(Q) to silence them
+# Use quiet_cmd_xxx, cmd_xxx to create nice output
+# use make V=1 to get verbose output
+
+ifdef V
+  ifeq ("$(origin V)", "command line")
+    KBUILD_VERBOSE = $(V)
+  endif
+endif
+ifndef KBUILD_VERBOSE
+  KBUILD_VERBOSE = 0
+endif
+
+ifeq ($(KBUILD_VERBOSE),1)
+  quiet =
+  Q =
+else
+  quiet=quiet_
+  Q = @
+endif
+
+# If the user is running make -s (silent mode), suppress echoing of
+# commands
+
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+  quiet=silent_
+endif
+
+export quiet Q KBUILD_VERBOSE
+
+# Do not print "Entering directory ..."
+MAKEFLAGS += --no-print-directory
+
+# Shorthand to call Kbuild.klibc
+klibc := -f $(srctree)/scripts/Kbuild.klibc obj
+
+# Very first target
+.PHONY: all klcc klibc
+all: klcc klibc
+
+$(objtree)/.config: $(srctree)/defconfig
+       @echo "defconfig has changed, please remove or edit .config"
+       @false
+
+$(KLIBCKERNELSRC):
+       @echo "Cannot find kernel sources."
+       @echo "Either make a 'linux' symlink point to a kernel tree "
+       @echo "configured for the $(KLIBCARCH) architecture or specify "
+       @echo "KLIBCKERNELSRC=<path> to the build."
+       @false
+
+rpmbuild = $(shell which rpmbuild 2>/dev/null || which rpm)
+
+klibc.spec: klibc.spec.in $(KLIBCSRC)/version
+       sed -e 's/@@VERSION@@/$(VERSION)/g' < $< > $@
+
+# Build klcc - it is the first target
+klcc: $(objtree)/.config
+       $(Q)$(MAKE) $(klibc)=klcc
+
+klibc: $(objtree)/.config
+       $(Q)$(MAKE) $(klibc)=.
+
+test: klibc
+       $(Q)$(MAKE) $(klibc)=usr/klibc/tests
+
+help:
+       @echo   'Cleaning targets:'
+       @echo   '  clean        - Remove most generated files'
+       @echo   '  mrproper     - Remove all generated files + config'
+       @echo   '  distclean    - mprproper + editor backup + patch files'
+       @echo   ''
+       @echo   'Build targets:'
+       @echo   'all            - Build all targets'
+       @echo   'install        - Install klibc'
+       @echo   'klcc           - Wrapper around gcc to compile against klibc'
+       @echo   'test           - Run klibc tests'
+       @echo
+       @echo   'Build options:'
+       @echo   'KLIBCKERNELSRC - Path to a configured linux tree'
+       @echo   'KLIBCKERNELOBJ - Path to kernel output dir (defaults to KLIBCKERNELSRC)'
+       @echo   'make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
+       @echo   'make V=2   [targets] 2 => give reason for rebuild of target'
+       @echo
+       @echo   'Sample invocation:'
+       @echo   'make  KLIBCKERNELSRC=`pwd`/../linux/usr/'
+
+###
+# allow one to say make dir/file.o
+# Caveat: works only for .c files where we have a Kbuild file in same dir
+%.o: %.c FORCE
+        $(Q)$(MAKE) $(klibc)=$(dir $<) $(dir $<)$(notdir $@)
+
+%.s: %.c FORCE
+        $(Q)$(MAKE) $(klibc)=$(dir $<) $(dir $<)$(notdir $@)
+
+%.i: %.c FORCE
+        $(Q)$(MAKE) $(klibc)=$(dir $<) $(dir $<)$(notdir $@)
+
+FORCE: ;
+###
+# clean: remove generated files
+# mrproper does a full cleaning including .config and linux symlink
+FIND_IGNORE := \( -name .git \) -prune -o
+quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),RM     $(wildcard $(rm-files)))
+      cmd_rmfiles = rm -f $(rm-files)
+clean:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.clean obj=.
+       $(Q)find . $(FIND_IGNORE) \
+               \( -name *.o -o -name *.a -o -name '.*.cmd' -o \
+                  -name '.*.d' -o -name '.*.tmp' \) \
+               -type f -print | xargs rm -f
+
+rm-files := $(objtree)/.config linux
+distclean mrproper: clean
+        $(Q)find . $(FIND_IGNORE) \
+               \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+               -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+               -o -name '.*.rej' -o -size 0 \
+               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+               -type f -print | xargs rm -f
+       $(call cmd,rmfiles)
+
+install: all
+       $(Q)$(MAKE) -f $(srctree)/scripts/Kbuild.install obj=.
+
+# This does all the prep work needed to turn a freshly exported git repository
+# into a release tarball tree
+release: klibc.spec
+       rm -f maketar.sh .config
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..6e2be32
--- /dev/null
+++ b/README
@@ -0,0 +1,33 @@
+Please see usr/klibc/README.klibc for build instructions and for the status of
+various platforms.
+
+
+
+klibc is archived at:
+
+       ftp://ftp.kernel.org/pub/linux/libs/klibc/
+
+There is a mailing list for klibc and early-userspace issues at:
+
+       klibc@zytor.com
+
+       http://www.zytor.com/mailman/listinfo/klibc/
+
+klibc is maintained in the git version control system.  The git
+repository can be viewed on the web at:
+
+       http://www.kernel.org/git/?p=libs/klibc/klibc.git;a=summary
+
+To clone the klibc repository using git:
+
+       git clone git://git.kernel.org/pub/scm/libs/klibc/klibc.git <workdir>
+
+To update an already cloned tree:
+
+       git pull
+
+For more information on git, see:
+
+       http://git.or.cz/
+       http://www.kernel.org/pub/software/scm/git/docs/tutorial.html
+       http://www.kernel.org/pub/software/scm/git/docs
diff --git a/contrib/klibc.m4 b/contrib/klibc.m4
new file mode 100644 (file)
index 0000000..66da30e
--- /dev/null
@@ -0,0 +1,93 @@
+# klibc.m4 serial 99\r
+## Copyright (C) 1995-2003 Free Software Foundation, Inc.\r
+## This file is free software, distributed under the terms of the GNU\r
+## General Public License.  As a special exception to the GNU General\r
+## Public License, this file may be distributed as part of a program\r
+## that contains a configuration script generated by Autoconf, under\r
+## the same distribution terms as the rest of that program.\r
+##\r
+## This file can can be used in projects which are not available under\r
+## the GNU General Public License or the GNU Library General Public\r
+## License but which still want to provide support for the GNU gettext\r
+## functionality.\r
+## Please note that the actual code of the KLIBC Library is partly covered\r
+## by the GNU Library General Public License, and party copyrighted by the\r
+## Regents of The University of California, and the rest is covered by a\r
+## MIT style license. \r
+\r
+# Authors:\r
+#   Martin Schlemmer <azarah@nosferatu.za.org>, 2005.\r
+\r
+\r
+# AC_CHECK_KLIBC\r
+# --------------\r
+# Check if the user wants KLIBC support enabled.  If so, set KLIBC=yes and\r
+# fill in KLIBC_PREFIX, KLIBC_BINDIR, KLIBC_SBINDIR, KLIBC_LIBDIR and\r
+# KLIBC_INCLUDEDIR.  CC is also set to the proper klcc executable.\r
+# NOTE:  This should be called before AC_PROG_CC, and before header, function\r
+#        or type checks.\r
+AC_DEFUN([AC_CHECK_KLIBC],\r
+[AC_BEFORE([$0], [AC_PROG_CC])\r
+AC_REQUIRE([AC_CANONICAL_HOST])\r
+AC_ARG_ENABLE([klibc],\r
+              [AS_HELP_STRING([--enable-klibc],\r
+                              [Enable linking to klibc [no].  You need at\r
+                               least klibc-1.0 or later for this.  Set KLCC\r
+                               to the absolute file name of klcc if not in\r
+                               the PATH])],\r
+              [KLIBC=$enableval], [KLIBC=no])\r
+AC_ARG_ENABLE([klibc-layout],\r
+              [AS_HELP_STRING([--enable-klibc-layout],\r
+                              [Enable installing binaries, libraries and\r
+                               headers into the klibc prefix [yes] ])],\r
+              [if test "X$KLIBC" != Xno; then\r
+                 KLIBC_LAYOUT=$enableval\r
+               else\r
+                 KLIBC_LAYOUT=no\r
+               fi],\r
+              [if test "X$KLIBC" != Xno; then\r
+                 KLIBC_LAYOUT=yes\r
+               else\r
+                 KLIBC_LAYOUT=no\r
+               fi])\r
+\r
+if test "X$KLIBC" != Xno; then\r
+  # Basic cross compiling support.  I do not think it is wise to use\r
+  # AC_CHECK_TOOL, because if we are cross compiling, we do not want\r
+  # just 'klcc' to be returned ...\r
+  if test "${host_alias}" != "${build_alias}"; then\r
+    AC_CHECK_PROGS([KLCC], [${host_alias}-klcc], [no])\r
+  else\r
+    AC_CHECK_PROGS([KLCC], [klcc], [no])\r
+  fi\r
+  if test "X$KLCC" = Xno; then\r
+    AC_MSG_ERROR([cannot find klibc frontend 'klcc'!])\r
+  fi\r
+\r
+  CC="$KLCC"\r
+  CFLAGS="-Os"\r
+\r
+  KLIBC_KCROSS="$($KLCC -print-klibc-kcross 2>/dev/null)"\r
+  KLIBC_PREFIX="$($KLCC -print-klibc-prefix 2>/dev/null)"\r
+  KLIBC_BIN_DIR="$($KLCC -print-klibc-bindir 2>/dev/null)"\r
+  KLIBC_SBIN_DIR="${KLIBC_PREFIX}/${KLIBC_KCROSS}sbin"\r
+  KLIBC_LIB_DIR="$($KLCC -print-klibc-libdir 2>/dev/null)"\r
+  KLIBC_INCLUDE_DIR="$($KLCC -print-klibc-includedir 2>/dev/null)"\r
+\r
+  if test "X$KLIBC_LAYOUT" != Xno; then\r
+    prefix="$KLIBC_PREFIX"\r
+    bindir="$KLIBC_BIN_DIR"\r
+    sbindir="$KLIBC_SBIN_DIR"\r
+    libdir="$KLIBC_LIB_DIR"\r
+    includedir="$KLIBC_INCLUDE_DIR"\r
+  fi\r
+\r
+  # At least KLIBC_LIB_DIR should be valid, else klibc is too old or\r
+  # something went wrong\r
+  if test ! -d "$KLIBC_LIB_DIR"; then\r
+    AC_MSG_ERROR([your klibc installation is too old or not functional!])\r
+  fi\r
+fi\r
+\r
+AC_SUBST(KLIBC)\r
+])# AC_CHECK_KLIBC\r
diff --git a/defconfig b/defconfig
new file mode 100644 (file)
index 0000000..04b98e9
--- /dev/null
+++ b/defconfig
@@ -0,0 +1,9 @@
+CONFIG_KLIBC=y
+CONFIG_KLIBC_ERRLIST=y
+CONFIG_KLIBC_ZLIB=y
+# CONFIG_KLIBC_ZIP is not set
+# i386 option
+CONFIG_REGPARM=y
+# ARM options
+# CONFIG_KLIBC_THUMB is not set
+# CONFIG_AEABI is not set
diff --git a/git-rm-for-kernel.sh b/git-rm-for-kernel.sh
new file mode 100755 (executable)
index 0000000..395692d
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+if [ -z "$RM" ]; then
+  export RM='git rm -rf'
+fi
+
+nuke () {
+    find "$@" -print | sort -r | xargs -rt $RM
+}
+
+nuke README Kbuild Makefile defconfig klibc.spec.in *.sh
+nuke contrib klcc
+
+# These files are either not needed or provided from the
+# kernel tree
+nuke scripts/Kbuild.include scripts/Kbuild.install
+nuke scripts/Makefile.*
+nuke scripts/basic
diff --git a/klcc/.gitignore b/klcc/.gitignore
new file mode 100644 (file)
index 0000000..b331920
--- /dev/null
@@ -0,0 +1,2 @@
+klcc
+klibc.config
diff --git a/klcc/Kbuild b/klcc/Kbuild
new file mode 100644 (file)
index 0000000..48c8b07
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# Build klcc
+#
+
+always := $(KLIBCCROSS)klcc
+
+$(obj)/$(KLIBCCROSS)klibc.config: $(src)/Kbuild \
+                                 $(srctree)/Makefile \
+                                  $(srctree)/scripts/Kbuild.klibc
+       @echo "  GEN     $@"
+       $(Q)rm -f $@
+       $(Q)echo 'ARCH=$(KLIBCARCH)' >> $@
+       $(Q)echo 'ARCHDIR=$(KLIBCARCHDIR)' >> $@
+       $(Q)echo 'CROSS=$(KLIBCROSS)' >> $@
+       $(Q)echo 'KCROSS=$(KCROSS)' >> $@
+       $(Q)echo 'CC=$(KLIBCCC)' >> $@
+       $(Q)echo 'LD=$(KLIBCLD)' >> $@
+       $(Q)echo 'REQFLAGS=$(filter-out -I%,$(KLIBCDEFS) $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS) $(KLIBCCPPFLAGS))' >> $@
+       $(Q)echo 'OPTFLAGS=$(KLIBCOPTFLAGS)' >> $@
+       $(Q)echo 'LDFLAGS=$(KLIBCLDFLAGS)' >> $@
+       $(Q)echo 'STRIP=$(KLIBCSTRIP)' >> $@
+       $(Q)echo 'STRIPFLAGS=$(KLIBCSTRIPFLAGS)' >> $@
+       $(Q)echo 'EMAIN=$(KLIBCEMAIN)' >> $@
+       $(Q)echo 'BITSIZE=$(KLIBCBITSIZE)' >> $@
+       $(Q)echo 'VERSION=$(shell cat $(srctree)/usr/klibc/version)' >> $@
+       $(Q)echo 'prefix=$(INSTALLDIR)' >> $@
+       $(Q)echo 'bindir=$(INSTALLDIR)/$(KCROSS)bin' >> $@
+       $(Q)echo 'libdir=$(INSTALLDIR)/$(KCROSS)lib' >> $@
+       $(Q)echo 'includedir=$(INSTALLDIR)/$(KCROSS)include' >> $@
+
+
+# Generate klcc
+targets := $(KLIBCCROSS)klcc
+
+quiet_cmd_klcc = GEN     $@
+      cmd_klcc = $(PERL) $< $(srctree)/$(src)/klcc.in \
+                            $(obj)/$(KLIBCCROSS)klibc.config \
+                            $(shell bash -c 'type -p $(PERL)') \
+                             > $@ || ( rm -f $@ ; exit 1 ) && \
+                             chmod a+x $@
+$(obj)/$(KLIBCCROSS)klcc: $(src)/makeklcc.pl $(src)/klcc.in \
+                          $(obj)/$(KLIBCCROSS)klibc.config
+       $(call if_changed,klcc)
+
+# Cleaning targets
+clean-files := $(KLIBCCROSS)klibc.config $(KLIBCCROSS)klcc
diff --git a/klcc/klcc.1 b/klcc/klcc.1
new file mode 100644 (file)
index 0000000..0186931
--- /dev/null
@@ -0,0 +1,118 @@
+.\" $Id: klcc.1,v 1.3 2005/04/19 23:27:46 hpa Exp $
+.\" -----------------------------------------------------------------------
+.\"
+.\"   Copyright 2005 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.
+.\"
+.\" -----------------------------------------------------------------------
+
+.TH klcc "1" "1 March 2005" "klibc" "H. Peter Anvin"
+.SH NAME
+klcc \- compile a program against klibc
+.SH SYNOPSIS
+.B klcc
+[\fIgcc options\fP]
+[\fB\-o\fP \fIoutfile\fP]
+\fIinfile...\fP
+.SH DESCRIPTION
+.PP
+.B klcc
+is a wrapper around
+.BR gcc (1)
+and
+.BR ld (1)
+which compiles and links a program against the
+.B klibc
+tiny C library.  It supports most
+.B gcc
+options.
+.PP
+Unlike
+.BR gcc ,
+.B klcc
+compiles with optimization on by default.  Furthermore, the
+optimization level used depends on whether or not
+.B \-g
+is specified, since
+.B klcc
+frequently uses options in the normal case which makes debugging
+impossible.  Therefore, compile without
+.BR \-g ,
+.BR \-O ,
+.B \-f
+or
+.B \-m
+option to use the default optimization level; this will generally
+result in the smallest binaries.  You may want to use
+.B \-s
+when linking, however.  Use
+.B \-O0
+to compile without any optimization whatsoever; this may not work depending
+on the version of
+.B gcc
+used.
+.TP
+.B \-nostdinc
+allows to turn off klibc include files.
+.PP
+Use the
+.B \-shared
+or
+.B \-static
+option to compile for and link against shared or static klibc.  Note
+that shared klibc only supports running against the exact same klibc
+binary as the binary was linked with.
+.PP
+In addition to standard
+.B gcc
+options,
+.B klcc
+supports options of the form \fB\-print-klibc-\fP\fIoption\fP,
+which prints the corresponding klibc configuration option.
+.SH AUTHOR
+Written by H. Peter Anvin <hpa@zytor.com>.
+.SH COPYRIGHT
+Copyright \(co 2005 H. Peter Anvin \- All Rights Reserved
+.PP
+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:
+.PP
+The above copyright notice and this permission notice shall
+be included in all copies or substantial portions of the Software.
+.PP
+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.
+.SH "SEE ALSO"
+.BR gcc (1)
diff --git a/klcc/klcc.in b/klcc/klcc.in
new file mode 100644 (file)
index 0000000..43d0984
--- /dev/null
@@ -0,0 +1,277 @@
+# -*- perl -*-
+
+use IPC::Open3;
+
+# Standard includes
+@includes = ("-I${prefix}/${KCROSS}include/arch/${ARCHDIR}",
+            "-I${prefix}/${KCROSS}include/bits${BITSIZE}",
+            "-I${prefix}/${KCROSS}include");
+
+# Default optimization options (for compiles without -g)
+@optopt =  @OPTFLAGS;
+@goptopt = ('-O');
+
+# Standard library directories
+@stdlibpath = ("-L${prefix}/${KCROSS}lib");
+
+# Options and libraries to pass to ld; shared versus static
+@staticopt = ("${prefix}/${KCROSS}lib/crt0.o");
+@staticlib = ("${prefix}/${KCROSS}lib/libc.a");
+@sharedopt = (@EMAIN, "${prefix}/${KCROSS}lib/interp.o");
+@sharedlib = ('-R', "${prefix}/${KCROSS}lib/libc.so");
+
+# Returns the language (-x option string) for a specific extension.
+sub filename2lang($) {
+    my ($file) = @_;
+
+    return 'c' if ( $file =~ /\.c$/ );
+    return 'c-header' if ( $file =~ /\.h$/ );
+    return 'cpp-output' if ( $file =~ /\.i$/ );
+    return 'c++-cpp-output' if ( $file =~ /\.ii$/ );
+    return 'objective-c' if ( $file =~ /\.m$/ );
+    return 'objc-cpp-output' if ( $file =~ /\.mi$/ );
+    return 'c++' if ( $file =~/\.(cc|cp|cxx|cpp|CPP|c\+\+|C)$/ );
+    return 'c++-header' if ( $file =~ /\.(hh|H)$/ );
+    return 'f77' if ( $file =~ /\.(f|for|FOR)$/ );
+    return 'f77-cpp-input' if ( $file =~ /\.(F|fpp|FPP)$/ );
+    return 'ratfor' if ( $file =~ /\.r$/ );
+
+    # Is this correct?
+    return 'ada' if ( $file =~ /\.(ads|adb)$/ );
+
+    return 'assembler' if ( $file =~ /\.s$/ );
+    return 'assembler-with-cpp' if ( $file =~/\.S$/ );
+
+    # Linker file; there is no option to gcc to assume something
+    # is a linker file, so we make up our own...
+    return 'obj';
+}
+
+# Produces a series of -x options and files
+sub files_with_lang($$) {
+    my($files, $flang) = @_;
+    my(@as) = ();
+    my($xopt) = 'none';
+    my($need);
+
+    foreach $f ( @{$files} ) {
+       $need = ${$flang}{$f};
+
+       # Skip object files
+       if ( $need ne 'obj' ) {
+           unless ( $xopt eq $need || $need eq 'stdin') {
+               push(@as, '-x', $need);
+               $xopt = $need;
+           }
+           push(@as, $f);
+       }
+    }
+
+    return @as;
+}
+
+# Convert a return value from system() to an exit() code
+sub syserr($) {
+    my($e) = @_;
+
+    return ($e & 0x7f) | 0x80 if ( $e & 0xff );
+    return $e >> 8;
+}
+
+# Run a program; printing out the command line if $verbose is set
+sub mysystem(@) {
+    print STDERR join(' ', @_), "\n" if ( $verbose );
+    my $cmd = shift;
+    open(INPUT, "<&STDIN");    # dup STDIN filehandle to INPUT
+    my $childpid = open3("<&INPUT", ">&STDOUT", ">&STDERR", $cmd, @_);
+    waitpid ($childpid, 0);
+    return $?;
+}
+
+#
+# Initialization
+#
+open(NULL, '+<', '/dev/null') or die "$0: cannot open /dev/null\n";
+
+#
+# Begin parsing options.
+#
+
+@ccopt = ();
+@ldopt = ();
+@libs  = ();
+
+@files = ();                   # List of files
+%flang = ();                   # Languages for files
+
+# This is 'c' for compile only, 'E' for preprocess only,
+# 'S' for compile to assembly.
+$operation = '';               # Compile and link
+
+# Current -x option.  If undefined, it means autodetect.
+undef $lang;
+
+$save_temps = 0;               # The -save-temps option
+$verbose = 0;                  # The -v option
+$shared = 0;                   # Are we compiling shared?
+$debugging = 0;                        # -g or -p option present?
+$strip = 0;                    # -s option present?
+undef $output;                 # -o option present?
+
+while ( defined($a = shift(@ARGV)) ) {
+    if ( $a !~ /^\-/ ) {
+       # Not an option.  Must be a filename then.
+       push(@files, $a);
+       $flang{$a} = $lang || filename2lang($a);
+    } elsif ( $a eq '-' ) {
+       # gcc gets its input from stdin
+       push(@files, $a);
+       # prevent setting -x
+       $flang{$a} = 'stdin'
+    } elsif ( $a =~ /^-print-klibc-(.*)$/ ) {
+       # This test must precede -print
+       if ( defined($conf{$1}) ) {
+           print ${$conf{$1}}, "\n";
+           exit 0;
+       } else {
+           die "$0: unknown option: $a\n";
+       }
+    } elsif ( $a =~ /^(-print|-dump|--help|--version|-v)/ ) {
+       # These share prefixes with some other options, so put this test early!
+       # Pseudo-operations; just pass to gcc and don't do anything else
+       push(@ccopt, $a);
+       $operation = 'c' if ( $operation eq '' );
+    } elsif ( $a =~ /^-Wl,(.*)$/ ) {
+       # -Wl used to pass options to the linker
+       push(@ldopt, split(/,/, $1));
+    } elsif ( $a =~ /^-([fmwWQdO]|std=|ansi|pedantic|M[GPD]|MMD)/ ) {
+       # Options to gcc
+       push(@ccopt, $a);
+    } elsif ( $a =~ /^-([DUI]|M[FQT])(.*)$/ ) {
+       # Options to gcc, which can take either a conjoined argument
+       # (-DFOO) or a disjoint argument (-D FOO)
+       push(@ccopt, $a);
+       push(@ccopt, shift(@ARGV)) if ( $2 eq '' );
+    } elsif ( $a eq '-include' ) {
+       # Options to gcc which always take a disjoint argument
+       push(@ccopt, $a, shift(@ARGV));
+    } elsif ( $a eq '-M' || $a eq '-MM' ) {
+       # gcc options, that force preprocessing mode
+       push(@ccopt, $a);
+       $operation = 'E';
+       } elsif ( $a =~ /^--param/ ) {
+       # support --param name=value and --param=name=value
+       my @values=split('=', $a);
+       if ( @values == 1 ) {
+               push(@ccopt, $a);
+               push(@ccopt, shift(@ARGV));
+       }
+       elsif ( @values == 3 ) {
+               push(@ccopt, $values[0]);
+               push(@ccopt, join('=', $values[1],$values[2]));
+       }
+    } elsif ( $a =~ /^-[gp]/ || $a eq '-p' ) {
+       # Debugging options to gcc
+       push(@ccopt, $a);
+       $debugging = 1;
+    } elsif ( $a eq '-v' ) {
+       push(@ccopt, $a);
+       $verbose = 1;
+    } elsif ( $a eq '-save-temps' ) {
+       push(@ccopt, $a);
+       $save_temps = 1;
+    } elsif ( $a =~ '^-([cSE])$' ) {
+       push(@ccopt, $a);
+       $operation = $1;
+    } elsif ( $a eq '-shared' ) {
+       $shared = 1;
+    } elsif ( $a eq '-static' ) {
+       $shared = 0;
+    } elsif ( $a eq '-s' ) {
+       $strip = 1;
+    } elsif ( $a eq '-o' ) {
+       $output = shift(@ARGV);
+    } elsif ( $a =~ /^\-x(.*)$/ ) {
+       # -x can be conjoined or disjoined
+       $lang = $1;
+       if ( $lang eq '' ) {
+           $lang = shift(@ARGV);
+       }
+    } elsif ( $a eq '-nostdinc' ) {
+       push(@ccopt, $a);
+       @includes = ();
+    } elsif ( $a =~ /^-([lL])(.*)$/ ) {
+       # Libraries
+       push(@libs, $a);
+       push(@libs, shift(@ARGV)) if ( $2 eq '' );
+    } else {
+       die "$0: unknown option: $a\n";
+    }
+}
+
+if ( $debugging ) {
+    @ccopt = (@REQFLAGS, @includes, @goptopt, @ccopt);
+} else {
+    @ccopt = (@REQFLAGS, @includes, @optopt, @ccopt);
+}
+
+if ( $operation ne '' ) {
+    # Just run gcc with the appropriate options
+    @outopt = ('-o', $output) if ( defined($output) );
+    $rv = mysystem($CC, @ccopt, @outopt, files_with_lang(\@files, \%flang));
+} else {
+    if ( scalar(@files) == 0 ) {
+       die "$0: No input files!\n";
+    }
+
+    @outopt = ('-o', $output || 'a.out');
+
+    @objs = ();
+    @rmobjs = ();
+
+    foreach $f ( @files ) {
+       if ( $flang{$f} eq 'obj' ) {
+           push(@objs, $f);
+       } else {
+           $fo = $f;
+           $fo =~ s/\.[^\/.]+$/\.o/;
+
+           die if ( $f eq $fo ); # safety check
+
+           push(@objs, $fo);
+           push(@rmobjs, $fo) unless ( $save_temps );
+
+           $rv = mysystem($CC, @ccopt, '-c', '-o', $fo, '-x', $flang{$f}, $f);
+
+           if ( $rv ) {
+               unlink(@rmobjs);
+               exit syserr($rv);
+           }
+       }
+    }
+
+    # Get the libgcc pathname for the *current* gcc
+    open(LIBGCC, '-|', $CC, @ccopt, '-print-libgcc-file-name')
+       or die "$0: cannot get libgcc filename\n";
+    $libgcc = <LIBGCC>;
+    chomp $libgcc;
+    close(LIBGCC);
+
+    if ( $shared ) {
+       $rv = mysystem($LD, @LDFLAGS, @sharedopt, @ldopt, @outopt, @objs,
+                      @libs, @stdlibpath, '--start-group', @sharedlib,
+                      $libgcc, '--end-group');
+    } else {
+       $rv = mysystem($LD, @LDFLAGS, @staticopt, @ldopt, @outopt, @objs,
+                      @libs, @stdlibpath, '--start-group', @staticlib,
+                      $libgcc, '--end-group');
+    }
+
+    unlink(@rmobjs);
+
+    if ( $strip && !$rv ) {
+       $rv = mysystem($STRIP, @STRIPFLAGS, $output);
+    }
+}
+
+exit syserr($rv);
diff --git a/klcc/makeklcc.pl b/klcc/makeklcc.pl
new file mode 100644 (file)
index 0000000..5945eb1
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+#
+# Combine klibc.config, klcc.in to produce a klcc script
+#
+# Usage: makeklcc klcc.in klibc.config perlpath
+#
+
+use File::Spec;
+
+($klccin, $klibcconf, $perlpath) = @ARGV;
+
+sub pathsearch($) {
+    my($file) = @_;
+    my(@path);
+    my($p,$pp);
+
+    if ( $file =~ /\// ) {
+       return File::Spec->rel2abs($file);
+    }
+
+    foreach $p ( split(/\:/, $ENV{'PATH'}) ) {
+       $pp = File::Spec->rel2abs(File::Spec->catpath(undef, $p, $file));
+       return $pp if ( -x $pp );
+    }
+
+    return undef;
+}
+
+print "#!${perlpath}\n";
+
+open(KLIBCCONF, "< $klibcconf\0")
+    or die "$0: cannot open $klibcconf: $!\n";
+while ( defined($l = <KLIBCCONF>) ) {
+    chomp $l;
+    if ( $l =~ /^([^=]+)\=\s*(.*)$/ ) {
+       $n = $1;  $s = $2;
+
+       if ( $n eq 'CC' || $n eq 'LD' || $n eq 'STRIP' ) {
+           $s1 = pathsearch($s);
+           die "$0: Cannot find $n: $s\n" unless ( defined($s1) );
+           $s = $s1;
+       }
+
+       print "\$$n = \"\Q$s\E\";\n";
+       print "\$conf{\'\L$n\E\'} = \\\$$n;\n";
+
+       print "\@$n = ("; $sep = '';
+       while ( $s =~ /^\s*(\S+)/ ) {
+           print $sep, "\"\Q$1\E\"";
+           $sep = ', ';
+           $s = "$'";
+       }
+       print ");\n";
+    }
+}
+close(KLIBCCONF);
+
+open(KLCCIN, "< $klccin\0")
+or die "$0: cannot open $klccin: $!\n";
+while ( defined($l = <KLCCIN>) ) {
+    print $l;
+}
+close(KLCCIN);
diff --git a/klibc.spec.in b/klibc.spec.in
new file mode 100644 (file)
index 0000000..e40afc3
--- /dev/null
@@ -0,0 +1,127 @@
+Summary: A minimal libc subset for use with initramfs.
+Name: klibc
+Version: @@VERSION@@
+Release: 1
+License: BSD/GPL
+Group: Development/Libraries
+URL: http://www.zytor.com/mailman/listinfo/klibc
+Source: http://www.kernel.org/pub/linux/libs/klibc-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildRequires: kernel >= 2.6.0, kernel-devel
+Packager: H. Peter Anvin <hpa@zytor.com>
+Prefix: /usr
+Vendor: Starving Linux Artists
+
+%define klibcdir  %{_prefix}/lib/klibc
+%define libdocdir %{_docdir}/%{name}-%{version}-%{release}
+%define bindocdir %{_docdir}/%{name}-utils-%{version}-%{release}
+
+%description
+%{name} 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.
+
+%package devel
+Summary: Libraries and tools needed to compile applications against klibc.
+Group: Development/Libraries
+Requires: klibc = %{version}-%{release}
+
+%description devel
+This package contains the link libraries, header files, and gcc
+wrapper scripts needed to compile applications against klibc.
+
+%package utils
+Summary: Small utilities built with klibc.
+Group: Utilities/System
+Requires: klibc = %{version}-%{release}
+
+%description utils
+This package contains a collection of programs that are linked against
+klibc.  These duplicate some of the functionality of a regular Linux
+toolset, but are typically much smaller than their full-function
+counterparts.  They are intended for inclusion in initramfs images and
+embedded systems.
+
+%prep
+%setup -q
+cp -dRs /lib/modules/`uname -r`/build/ ./linux
+# Shouldn't need this when getting the build tree from /lib/modules
+# make -C linux defconfig ARCH=%{_target_cpu}
+# make -C linux prepare ARCH=%{_target_cpu}
+# Deal with braindamage in RedHat's kernel-source RPM
+rm -f linux/include/linux/config.h
+cat <<EOF > linux/include/linux/config.h
+#ifndef _LINUX_CONFIG_H
+#define _LINUX_CONFIG_H
+
+#include <linux/autoconf.h>
+
+#endif
+EOF
+mkdir -p %{buildroot}
+
+%build
+make %{_smp_mflags} \
+       KLIBCARCH=%{_target_cpu} prefix=%{_prefix} bindir=%{_bindir} \
+       INSTALLDIR=%{klibcdir} mandir=%{_mandir} INSTALLROOT=%{buildroot}
+
+%install
+rm -rf %{buildroot}
+make  KLIBCARCH=%{_target_cpu} prefix=%{_prefix} bindir=%{_bindir} \
+       INSTALLDIR=%{klibcdir} mandir=%{_mandir} INSTALLROOT=%{buildroot} \
+       install
+
+# Make the .so file in /lib a hardlink (they will be expanded as two
+# files automatically if it crosses filesystems when extracted.)
+ln -f %{buildroot}%{klibcdir}/lib/klibc-*.so %{buildroot}/lib
+
+# Install the docs
+mkdir -p %{buildroot}%{bindocdir} %{buildroot}%{libdocdir}
+install -m 444 README %{buildroot}%{libdocdir}
+install -m 444 usr/klibc/README.klibc %{buildroot}%{libdocdir}
+install -m 444 usr/klibc/arch/README.klibc.arch %{buildroot}%{libdocdir}
+
+install -m 444 usr/gzip/COPYING %{buildroot}%{bindocdir}/COPYING.gzip
+install -m 444 usr/gzip/README %{buildroot}%{bindocdir}/README.gzip
+install -m 444 usr/kinit/ipconfig/README.ipconfig %{buildroot}%{bindocdir}
+install -m 444 usr/kinit/README %{buildroot}%{bindocdir}/README.kinit
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+#
+# Note: libc.so and interp.o are technically -devel files, but
+# put them in this package until we can make really, really sure
+# the dependency system can avoid confusion.  (In fact, it would be
+# good to eventually get them out of here, so that multiple runtimes
+# can be installed should it be necessary.)
+#
+%files
+%defattr(-,root,root,-)
+/lib/klibc-*.so
+%{klibcdir}/lib/*.so
+%{klibcdir}/lib/interp.o
+
+%files devel
+%defattr(-,root,root,-)
+%{klibcdir}/include
+%{klibcdir}/lib/*.a
+%{klibcdir}/lib/crt0.o
+%{_bindir}/klcc
+%doc %{_mandir}/man1/*
+%doc %{libdocdir}/*
+
+%files utils
+%defattr(-,root,root,-)
+%{klibcdir}/bin
+%doc %{bindocdir}/*
+
+%changelog
+* Tue Mar 1 2005 H. Peter Anvin <hpa@zytor.com>
+- New "make install" scheme, klcc
+
+* Tue Jul 6 2004 H. Peter Anvin <hpa@zytor.com>
+- Update to use kernel-source RPM for the kernel symlink.
+
+* Sat Nov 29 2003 Bryan O'Sullivan <bos@serpentine.com> -
+- Initial build.
diff --git a/makerpm.sh b/makerpm.sh
new file mode 100755 (executable)
index 0000000..1e3a6f0
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash -xe
+#
+# Make an rpm from the current git repository
+#
+
+[ -z "$tmpdir" ] && export tmpdir=/var/tmp
+
+./maketar.sh
+rpmbuild -ta $tmpdir/klibc-`cat usr/klibc/version`.tar.gz
diff --git a/maketar.sh b/maketar.sh
new file mode 100755 (executable)
index 0000000..deed7b3
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash -xe
+#
+# Make a tarball from the current git repository
+#
+
+[ -z "$tmpdir" ] && tmpdir=/var/tmp
+
+tmp=$tmpdir/klibc.$$
+rm -rf $tmp
+cg-export $tmp
+cd $tmp
+make release
+version=`cat usr/klibc/version`
+rm -rf $tmpdir/klibc-$version
+mv $tmp $tmpdir/klibc-$version
+cd ..
+rm -f klibc-$version.tar*
+tar cvvf klibc-$version.tar klibc-$version
+gzip -9 klibc-$version.tar
+rm -rf klibc-$version
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
new file mode 100644 (file)
index 0000000..a048ec7
--- /dev/null
@@ -0,0 +1,278 @@
+####
+# kbuild: Generic definitions
+
+# Convenient variables
+comma   := ,
+squote  := '
+empty   :=
+space   := $(empty) $(empty)
+
+###
+# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
+dot-target = $(dir $@).$(notdir $@)
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(dot-target).d)
+
+###
+# filename of target with directory and extension stripped
+basetarget = $(basename $(notdir $@))
+
+###
+# filename of first prerequisite with directory and extension stripped
+baseprereq = $(basename $(notdir $<))
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+###
+# Easy method for doing a status message
+       kecho := :
+ quiet_kecho := echo
+silent_kecho := :
+kecho := $($(quiet)kecho)
+
+###
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+#      echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+#      $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+# - stdin is piped in from the first prerequisite ($<) so one has
+#   to specify a valid file as first prerequisite (often the kbuild file)
+define filechk
+       $(Q)set -e;                             \
+       $(kecho) '  CHK     $@';                \
+       mkdir -p $(dir $@);                     \
+       $(filechk_$(1)) < $< > $@.tmp;          \
+       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
+               rm -f $@.tmp;                   \
+       else                                    \
+               $(kecho) '  UPD     $@';        \
+               mv -f $@.tmp $@;                \
+       fi
+endef
+
+######
+# gcc support functions
+# See documentation in Documentation/kbuild/makefiles.txt
+
+# cc-cross-prefix
+# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
+# Return first prefix where a prefix$(CC) is found in PATH.
+# If no $(CC) found in PATH with listed prefixes return nothing
+cc-cross-prefix =  \
+       $(word 1, $(foreach c,$(1),                                   \
+               $(shell set -e;                                       \
+               if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \
+                       echo $(c);                                    \
+               fi)))
+
+# output directory for tests below
+TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
+
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e;              \
+       TMP="$(TMPOUT).$$$$.tmp";       \
+       TMPO="$(TMPOUT).$$$$.o";        \
+       if ($(1)) >/dev/null 2>&1;      \
+       then echo "$(2)";               \
+       else echo "$(3)";               \
+       fi;                             \
+       rm -f "$$TMP" "$$TMPO")
+
+# as-option
+# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+
+as-option = $(call try-run,\
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2))
+
+# as-instr
+# Usage: cflags-y += $(call as-instr,instr,option1,option2)
+
+as-instr = $(call try-run,\
+       printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+
+# cc-option
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
+
+cc-option = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
+
+# cc-option-align
+# Prefix align with either -falign or -malign
+cc-option-align = $(subst -functions=0,,\
+       $(call cc-option,-falign-functions=0,-malign-functions=0))
+
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
+# cc-version
+# Usage gcc-ver := $(call cc-version)
+cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
+
+# cc-fullversion
+# Usage gcc-ver := $(call cc-fullversion)
+cc-fullversion = $(shell $(CONFIG_SHELL) \
+       $(srctree)/scripts/gcc-version.sh -p $(CC))
+
+# cc-ifversion
+# Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
+cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
+
+# cc-ldoption
+# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both)
+cc-ldoption = $(call try-run,\
+       $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2))
+
+# ld-option
+# Usage: LDFLAGS += $(call ld-option, -X)
+ld-option = $(call try-run,\
+       $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
+
+# ar-option
+# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
+# Important: no spaces around options
+ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+
+######
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
+# Usage:
+# $(Q)$(MAKE) $(build)=dir
+build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Kbuild.klibc obj=
+# Usage:
+# $(Q)$(MAKE) $(klibc)=dir
+klibc := -f $(srctree)/scripts/Kbuild.klibc obj
+
+# Prefix -I with $(srctree) if it is not an absolute path.
+# skip if -I has no parameter
+addtree = $(if $(patsubst -I%,%,$(1)), \
+$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
+
+# Find all -I options and call addtree
+flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+       echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
+# printing commands
+cmd = @$(echo-cmd) $(cmd_$(1))
+
+# Add $(obj)/ for paths that are not absolute
+objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
+
+###
+# if_changed      - execute command if any prerequisite is newer than
+#                   target, or command line has changed
+# if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
+#                   including used config symbols
+# if_changed_rule - as if_changed but execute rule instead
+# See Documentation/kbuild/makefiles.txt for more info
+
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result is empty string if equal.
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+else
+arg-check = $(if $(strip $(cmd_$@)),,1)
+endif
+
+# >'< substitution is for echo to work,
+# >$< substitution to preserve $ when reloading .cmd file
+# note: when using inline perl scripts [perl -e '...$$t=1;...']
+# in $(cmd_xxx) double $$ your perl vars
+make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+
+# Execute command if command has changed or prerequisite(s) are updated.
+#
+if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
+       @set -e;                                                             \
+       $(echo-cmd) $(cmd_$(1));                                             \
+       echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+# Execute the command and also postprocess generated .d dependencies file.
+if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
+       @set -e;                                                             \
+       $(echo-cmd) $(cmd_$(1));                                             \
+       scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
+       rm -f $(depfile);                                                    \
+       mv -f $(dot-target).tmp $(dot-target).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# Will check if $(cmd_foo) or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
+if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
+       @set -e;                                                             \
+       $(rule_$(1)))
+
+###
+# why - tell why a a target got build
+#       enabled by make V=2
+#       Output (listed in the order they are checked):
+#          (1) - due to target is PHONY
+#          (2) - due to target missing
+#          (3) - due to: file1.h file2.h
+#          (4) - due to command line change
+#          (5) - due to missing .cmd file
+#          (6) - due to target not in $(targets)
+# (1) PHONY targets are always build
+# (2) No target, so we better build it
+# (3) Prerequisite is newer than target
+# (4) The command line stored in the file named dir/.target.cmd
+#     differed from actual command line. This happens when compiler
+#     options changes
+# (5) No dir/.target.cmd file (used to store command line)
+# (6) No dir/.target.cmd file and target not listed in $(targets)
+#     This is a good hint that there is a bug in the kbuild file
+ifeq ($(KBUILD_VERBOSE),2)
+why =                                                                        \
+    $(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
+        $(if $(wildcard $@),                                                 \
+            $(if $(strip $(any-prereq)),- due to: $(any-prereq),             \
+                $(if $(arg-check),                                           \
+                    $(if $(cmd_$@),- due to command line change,             \
+                        $(if $(filter $@, $(targets)),                       \
+                            - due to missing .cmd file,                      \
+                            - due to $(notdir $@) not in $$(targets)         \
+                         )                                                   \
+                     )                                                       \
+                 )                                                           \
+             ),                                                              \
+             - due to target missing                                         \
+         )                                                                   \
+     )
+
+echo-why = $(call escsq, $(strip $(why)))
+endif
diff --git a/scripts/Kbuild.install b/scripts/Kbuild.install
new file mode 100644 (file)
index 0000000..78c30aa
--- /dev/null
@@ -0,0 +1,113 @@
+#
+# Install klibc
+#
+# File is logically seperated in two pieces.
+# First piece is used when during a recursive descend of the klibc tree
+# and second piece is used to do the final steps in the install
+# If KLIBC_INSTALL is defined it tells us we are descending and we
+# use first piece of the file.
+
+# This indicates the location of the final version of the shared library.
+# THIS MUST BE AN ABSOLUTE PATH WITH NO FINAL SLASH.
+# Leave this empty to make it the root.
+#
+SHLIBDIR = /lib
+
+# First rule
+.PHONY: __install install-rule
+__install:
+
+# Install commands
+install-data := install -m 644
+install-lib  := install -m 755
+install-bin  := install -m 755
+
+# Install command
+quiet_cmd_install = INSTALL $(install-y)
+      cmd_install = $(install-bin) $(install-y) \
+                                   $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)bin
+
+ifeq ($(KLIBC_INSTALL),1)
+# First part - we are descending..
+
+# Reset variables (to get right type of assingment)
+subdir- :=
+
+# Include Kbuild file
+include $(srctree)/scripts/Kbuild.include
+include $(srctree)/$(obj)/Kbuild
+
+# Directories to visit
+# First find directories specified in lib-?, static-y and shared-y
+find-dir = $(patsubst %/,%,$(filter %/, $(1)))
+
+__subdir := $(call find-dir, $(lib-))
+__subdir += $(call find-dir, $(lib-y))
+
+__subdir += $(foreach e, $(static-y), $(call find-dir, $(e)))
+__subdir += $(foreach e, $(shared-y), $(call find-dir, $(e)))
+
+# Use subdir- in Kbuild file to tell kbuild to visit a specific dir
+subdir-  += $(__subdir)
+
+# Remove duplicates and add prefix
+subdir- := $(addprefix $(obj)/,$(sort $(subdir-)))
+
+# Files to install
+install-y := $(strip $(addprefix $(obj)/, $(install-y)))
+
+__install: $(subdir-) install-rule
+ifneq ($(install-y),)
+       $(call cmd,install)
+else
+       @:
+endif
+
+# Descending
+.PHONY: $(subdir-)
+$(subdir-):
+       $(Q)$(MAKE) KLIBC_INSTALL=1 \
+                   -f $(srctree)/scripts/Kbuild.install obj=$@
+
+# If quiet is set, only print short version of command
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
+
+
+else
+##########################################################################
+# This is the first time this file is invoked, so kick off the
+# install process.
+# First we descend all sub-directories to let them do their install.
+# Second we do the final install steps.
+
+# Do actual install as a three steps approach
+# 1) Create directories, install headers and man pages
+# 2) Tell that we now install binaries
+# 3) Install binaries by descending
+.PHONY: header footer descend
+header:
+       $(Q)echo "  INSTALL headers + man pages to $(INSTALLROOT)$(INSTALLDIR)"
+       $(Q)mkdir -p $(INSTALLROOT)$(bindir)
+       $(Q)mkdir -p $(INSTALLROOT)$(mandir)/man1
+       $(Q)mkdir -p $(INSTALLROOT)$(SHLIBDIR)
+       $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)
+       $(Q)-rm -rf $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include
+       $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include
+       $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)lib
+       $(Q)mkdir -p $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)bin
+       $(Q)$(MAKE) -C $(KLIBCKERNELSRC) ARCH=$(KLIBCARCH) INSTALL_HDR_PATH=$(INSTALLROOT)$(INSTALLDIR)/$(KCROSS) headers_install
+       $(Q)cp -rf usr/include/. $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include/.
+       $(Q)chmod -R a+rX $(INSTALLROOT)$(INSTALLDIR)/$(KCROSS)include
+       $(Q)$(install-data) $(srctree)/klcc/klcc.1 $(INSTALLROOT)$(mandir)/man1/$(KCROSS)klcc.1
+       $(Q)$(install-bin) $(objtree)/klcc/$(KCROSS)klcc $(INSTALLROOT)$(bindir)
+
+footer: header
+       $(Q)echo "  INSTALL binaries to $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)bin"
+
+descend: footer
+       $(Q)$(MAKE) KLIBC_INSTALL=1 \
+                   -f $(srctree)/scripts/Kbuild.install obj=$(obj)
+
+__install: descend
+       @:
+endif
diff --git a/scripts/Kbuild.klibc b/scripts/Kbuild.klibc
new file mode 100644 (file)
index 0000000..f500d53
--- /dev/null
@@ -0,0 +1,421 @@
+# ==========================================================================
+# Support for building klibc programs and klibc library
+# ==========================================================================
+#
+# To create a kbuild file for a userspace program do the following:
+#
+# Kbuild:
+#
+# static-y := cat
+# # This will compile a file named cat.c -> the executable 'cat'
+# # The executable will be linked statically
+#
+# shared-y := cats
+# # This will compile a file named cats.c -> the executable 'cats'
+# # The executable will be linked shared
+#
+# If the userspace program consist of composite files do the following:
+# Kbuild:
+#
+# static-y := kinit
+# kinit-y  := main.o netdev.c
+# So kinit will be linked statically using the two .o files
+# specified with kinit-y.
+#
+# Are part of the program located in a sub-directory do like this:
+# kinit-y += ipconfig/
+#
+# And in the subdirectory:
+# ipconfig/Kbuild:
+# lib-y := packet.o dhcp_proto.o
+# # All .o files listed with lib-y will be used to create a single .a file.
+# # The .a file is created before any subdirectories are visited so it
+# # may be used in the sub-directory programs.
+#
+#####
+# For a klibc libary file do like this
+# klibc/Kbuild
+# klib-y := error.o pipe.o zlib/
+#
+#####
+# Handling of compiler/linker options
+#
+# To set directory wide CFLAGS use:
+# EXTRA_KLIBCCFLAGS := -DDEBUG
+# To set directory wide AFLAGS use:
+# EXTRA_KLIBCAFLAGS := -DDEBUG
+#
+# To set target specific CFLAGS (for .c files) use
+# KLIBCCFLAGS-main.o := -DDEBUG=3
+# To set target specific AFLAGS (for .s files) use
+# KLIBCAFLAGS-main.o := -DDEBUG=3
+
+src := $(obj)
+# Preset target and make sure it is a ':=' variable
+targets :=
+
+.phony: __build
+__build:
+
+# Read .config if it exist, otherwise ignore
+-include $(objtree)/.config
+
+# Generic Kbuild routines
+include $(srctree)/scripts/Kbuild.include
+
+# Defines used when compiling early userspace (klibc programs)
+# ---------------------------------------------------------------------------
+
+KLIBCREQFLAGS     := $(call cc-option, -fno-stack-protector, ) \
+                     $(call cc-option, -fwrapv, )
+KLIBCARCHREQFLAGS :=
+KLIBCOPTFLAGS     :=
+KLIBCWARNFLAGS    := -W -Wall -Wno-sign-compare -Wno-unused-parameter
+KLIBCSHAREDFLAGS  :=
+KLIBCBITSIZE      :=
+KLIBCLDFLAGS      :=
+KLIBCCFLAGS       :=
+
+# Defaults for arch to override
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)/arch/$(KLIBCARCH)/include
+
+# Arch specific definitions for klibc
+include $(srctree)/$(KLIBCSRC)/arch/$(KLIBCARCHDIR)/MCONFIG
+
+# include/asm-* architecture
+KLIBCASMARCH     ?= $(KLIBCARCH)
+
+# klibc version
+KLIBCMAJOR        := $(shell cut -d. -f1 $(srctree)/usr/klibc/version)
+KLIBCMINOR        := $(shell cut -d. -f2 $(srctree)/usr/klibc/version)
+
+# binutils
+KLIBCLD          := $(LD)
+KLIBCCC          := $(CC)
+KLIBCAR          := $(AR)
+
+# klibc-ar is a macro that invokes KLIBCAR and takes 2 arguments of ar commands.
+# The second will be used for reproducible builds, the first otherwise.
+klibc-ar = $(KLIBCAR) $(if $(KBUILD_REPRODUCIBLE),$(2),$(1))
+
+KLIBCRANLIB      := $(call klibc-ar,s,Ds)
+KLIBCSTRIP       := $(STRIP)
+KLIBCNM          := $(NM)
+KLIBCOBJCOPY     := $(OBJCOPY)
+KLIBCOBJDUMP     := $(OBJDUMP)
+
+# klibc include paths
+KLIBCCPPFLAGS    := -nostdinc -iwithprefix include \
+                   -I$(KLIBCINC)/arch/$(KLIBCARCHDIR)  \
+                    -I$(KLIBCINC)/bits$(KLIBCBITSIZE)  \
+                   -I$(KLIBCOBJ)/../include            \
+                    -I$(KLIBCINC)
+# kernel include paths
+KLIBCKERNELSRC  ?= $(srctree)
+KLIBCKERNELOBJ  ?= $(objtree)
+KLIBCCPPFLAGS    += -I$(KLIBCKERNELSRC)/include                                    \
+                     $(if $(KBUILD_SRC),-I$(KLIBCKERNELOBJ)/include2       \
+                      -I$(KLIBCKERNELOBJ)/include -I$(srctree)/include)    \
+                    $(KLIBCARCHINCFLAGS)
+
+# klibc definitions
+KLIBCDEFS        += -D__KLIBC__=$(KLIBCMAJOR)          \
+                   -D__KLIBC_MINOR__=$(KLIBCMINOR)    \
+                   -D_BITSIZE=$(KLIBCBITSIZE)
+KLIBCCPPFLAGS    += $(KLIBCDEFS)
+KLIBCCFLAGS      += $(KLIBCCPPFLAGS) $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS)  \
+                    $(KLIBCOPTFLAGS) $(KLIBCWARNFLAGS)
+KLIBCAFLAGS      += -D__ASSEMBLY__ $(KLIBCCFLAGS)
+KLIBCSTRIPFLAGS  += --strip-all -R .comment -R .note
+
+KLIBCLIBGCC_DEF  := $(shell $(KLIBCCC) $(KLIBCCFLAGS) --print-libgcc)
+KLIBCLIBGCC     ?= $(KLIBCLIBGCC_DEF)
+KLIBCCRT0        := $(KLIBCOBJ)/arch/$(KLIBCARCHDIR)/crt0.o
+KLIBCLIBC        := $(KLIBCOBJ)/libc.a
+KLIBCCRTSHARED   := $(KLIBCOBJ)/interp.o
+KLIBCLIBCSHARED  := $(KLIBCOBJ)/libc.so
+# How to tell the linker main() is the entrypoint
+KLIBCEMAIN      ?= -e main
+
+#
+# This indicates the location of the final version of the shared library.
+# THIS MUST BE AN ABSOLUTE PATH WITH NO FINAL SLASH.
+# Leave this empty to make it the root.
+#
+SHLIBDIR = /lib
+
+export KLIBCLD KLIBCCC KLIBCAR KLIBCSTRIP KLIBCNM
+export KLIBCCFLAGS KLIBCAFLAGS KLIBCLIBGCC KLIBCSHAREDFLAGS KLIBCSTRIPFLAGS
+export KLIBCCRT0 KLIBCLIBC SHLIBDIR
+
+# Add $(obj)/ for paths that is not absolute
+objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
+
+# Kbuild file in the directory that is being build
+include $(srctree)/$(obj)/Kbuild
+
+#####
+# static-y + shared-y handling
+kprogs := $(static-y) $(shared-y)
+# kprogs based on a single .o file (with same name + .o)
+kprog-objs := $(foreach p, $(kprogs), $(if $($(p)-y),,$(p)))
+kprog-objs := $(addsuffix .o, $(kprog-objs))
+# kprogs which is based on several .o files
+kprog-multi := $(foreach p, $(kprogs), $(if $($(p)-y),$(p)))
+# objects used for kprogs with more then one .o file
+kprog-objs += $(foreach p, $(kprog-multi), $($(p)-y))
+# objects build in this dir
+kprog-real-objs := $(patsubst %/,,$(kprog-objs))
+# Directories we need to visit before kprogs-objs are up-to-date
+kprog-dirs :=  $(patsubst %/,%,$(filter %/, $(kprog-objs)))
+# replace all dir/ with dir/lib.a
+kprog-objs := $(patsubst %/, %/lib.a, $(kprog-objs))
+
+targets += $(static-y) $(shared-y)
+
+#####
+# klib-y handling
+# .o files to build in this dir
+klib-real-objs := $(patsubst %/,,$(klib-y))
+# Directories we need to visit before libs are up-to-date
+klib-dirs := $(patsubst %/,%,$(filter %/, $(klib-y)))
+# replace all dir/ with dir/klib.list
+klib-objs := $(patsubst %/, %/klib.list, $(klib-y))
+
+# $(output-dirs) are a list of directories that contain object files
+output-dirs := $(dir $(kprog-dirs) $(kprog-objs))
+output-dirs += $(foreach f, $(hostprogs-y) $(targets), \
+               $(if $(dir $(f)), $(dir $(f))))
+output-dirs += $(dir $(klib-objs))
+output-dirs := $(strip $(sort $(filter-out ./,$(output-dirs))))
+
+# prefix so we get full dir
+static-y        := $(addprefix $(obj)/,$(static-y))
+shared-y        := $(addprefix $(obj)/,$(shared-y))
+kprog-objs      := $(addprefix $(obj)/,$(kprog-objs))
+kprog-real-objs := $(addprefix $(obj)/,$(kprog-real-objs))
+output-dirs     := $(addprefix $(obj)/,$(output-dirs))
+kprog-dirs      := $(addprefix $(obj)/,$(kprog-dirs))
+subdir-y        := $(addprefix $(obj)/,$(subdir-y))
+always          := $(addprefix $(obj)/,$(always))
+targets         := $(addprefix $(obj)/,$(targets))
+lib-y           := $(addprefix $(obj)/,$(lib-y))
+klib-y          := $(addprefix $(obj)/,$(klib-y))
+klib-objs       := $(addprefix $(obj)/,$(klib-objs))
+klib-real-objs  := $(addprefix $(obj)/,$(klib-real-objs))
+klib-dirs       := $(addprefix $(obj)/,$(klib-dirs))
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+__klibccflags    = $(KLIBCCFLAGS) $(EXTRA_KLIBCCFLAGS) $(KLIBCCFLAGS_$(*F).o)
+__klibcaflags    = $(KLIBCAFLAGS) $(EXTRA_KLIBCAFLAGS) $(KLIBCAFLAGS_$(*F).o)
+
+_klibccflags    = $(call flags,__klibccflags)
+_klibcaflags    = $(call flags,__klibcaflags)
+
+klibccflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibccflags)
+klibcaflags     = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(_klibcaflags)
+
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+# Create directories for object files if directory does not exist
+# Needed when lib-y := dir/file.o syntax is used
+_dummy := $(foreach d,$(output-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
+
+# Do we have to make a lib.a in this dir?
+ifneq ($(strip $(lib-y) $(lib-n) $(lib-)),)
+lib-target := $(obj)/lib.a
+endif
+
+__build: $(subdir-y) $(lib-target) $(always)
+       $(Q):
+
+# Compile C sources (.c)
+# ---------------------------------------------------------------------------
+
+quiet_cmd_cc_s_c = KLIBCCC $@
+      cmd_cc_s_c = $(KLIBCCC) $(klibccflags) -S -o $@ $<
+
+%.s: %.c FORCE
+       $(call if_changed_dep,cc_s_c)
+
+quiet_cmd_cc_o_c = KLIBCCC $@
+      cmd_cc_o_c = $(KLIBCCC) $(klibccflags) -c -o $@ $<
+
+%.o: %.c FORCE
+       $(call if_changed_dep,cc_o_c)
+
+quiet_cmd_cc_i_c = CPP     $@
+      cmd_cc_i_c = $(KLIBCCC) -E $(klibccflags) -o $@ $<
+%.i: %.c FORCE
+       $(call if_changed_dep,cc_i_c)
+
+# Compile assembler sources (.S)
+# ---------------------------------------------------------------------------
+
+quiet_cmd_as_o_S = KLIBCAS $@
+      cmd_as_o_S = $(KLIBCCC) $(klibcaflags) -c -o $@ $<
+
+%.o: %.S FORCE
+       $(call if_changed_dep,as_o_S)
+
+targets += $(real-objs-y)
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef lib-target
+quiet_cmd_link_o_target = LD      $@
+# If the list of objects to link is empty, just create an empty lib.a
+cmd_link_o_target = $(if $(strip $(lib-y)),\
+                    rm -f $@; $(call klibc-ar,cru,Dcr) $@ $(filter $(lib-y), $^),\
+                    rm -f $@; $(call klibc-ar,crs,Dcrs) $@)
+
+$(lib-target): $(lib-y) FORCE
+       $(call if_changed,link_o_target)
+targets += $(lib-target) $(lib-y)
+endif # lib-target
+
+#
+# Create klib.list
+#
+# Do we have to create a klibc library file in this dir?
+ifneq ($(strip $(klib-y) $(klib-n) $(klib-)),)
+klib-target := $(obj)/klib.list
+endif
+
+ifdef klib-target
+# include this in build
+__build: $(klib-target) $(klib-dirs)
+
+# descend if needed
+$(sort $(addsuffix /klib.list,$(klib-dirs))): $(klib-dirs) ;
+
+# create klib.list
+quiet_cmd_klib-list = LIST    $@
+      cmd_klib-list = echo $(klib-real-objs) > $@
+$(klib-target): $(klib-objs) FORCE
+       $(call if_changed,klib-list)
+targets += $(klib-target) $(klib-real-objs)
+endif # klib-target
+
+ifdef kprogs
+# Compile klibc-programs for the target
+# ===========================================================================
+
+__build : $(kprog-dirs) $(static-y) $(shared-y)
+
+# Descend if needed
+$(sort $(addsuffix /lib.a,$(kprog-dirs))): $(kprog-dirs) ;
+
+# Define dependencies for link of progs
+# For the simple program:
+#      file.o => file
+# A program with multiple objects
+#      filea.o, fileb.o => file
+# A program with .o files in another dir
+#      dir/lib.a filea.o => file
+
+stripobj  = $(subst $(obj)/,,$@)
+addliba   = $(addprefix $(obj)/, $(patsubst %/, %/lib.a, $(1)))
+link-deps = $(if $($(stripobj)-y), $(call addliba, $($(stripobj)-y)), $@.o) \
+           $(call objectify,$($(stripobj)-lib))
+
+quiet_cmd_ld-static = KLIBCLD $@
+      cmd_ld-static = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@         \
+                       $(EXTRA_KLIBCLDFLAGS)                   \
+                       $(KLIBCCRT0)                            \
+                      --start-group                            \
+                       $(link-deps)                            \
+                       $(KLIBCLIBC)                            \
+                      $(KLIBCLIBGCC)                           \
+                      --end-group ;                            \
+                      cp -f $@ $@.g ;                          \
+                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@
+
+
+$(static-y): $(kprog-objs) $(lib-target) $(KLIBCCRT0) $(KLIBCLIBC) FORCE
+       $(call if_changed,ld-static)
+
+quiet_cmd_ld-shared = KLIBCLD $@
+      cmd_ld-shared = $(KLIBCLD) $(KLIBCLDFLAGS) -o $@         \
+                       $(EXTRA_KLIBCLDFLAGS)                   \
+                       $(KLIBCEMAIN) $(KLIBCCRTSHARED)         \
+                       --start-group                           \
+                       $(link-deps)                            \
+                       -R $(KLIBCLIBCSHARED)                   \
+                      $(KLIBCLIBGCC)                           \
+                      --end-group ;                            \
+                      cp -f $@ $@.g ;                          \
+                      $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $@
+
+
+$(shared-y): $(kprog-objs) $(lib-target) $(KLIBCCRTSHARED) \
+                                         $(KLIBCLIBCSHARED) FORCE
+       $(call if_changed,ld-shared)
+
+# Do not try to build KLIBC libaries if we are building klibc
+ifeq ($(klibc-build),)
+$(KLIBCCRT0) $(KLIBCLIBC): ;
+$(KLIBCCRTSHARED) $(KLIBCLIBCSHARED): ;
+endif
+
+targets += $(kprog-real-objs)
+endif
+
+# Compile programs on the host
+# ===========================================================================
+ifdef hostprogs-y
+include $(srctree)/scripts/Makefile.host
+endif
+
+# Descending
+# ---------------------------------------------------------------------------
+
+.PHONY: $(subdir-y) $(kprog-dirs) $(klib-dirs)
+$(sort $(subdir-y) $(kprog-dirs) $(klib-dirs)): $(lib-target)
+       $(Q)$(MAKE) $(klibc)=$@
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+
+FORCE:
+
+# Linking
+# Create a reloctable composite object file
+# ---------------------------------------------------------------------------
+quiet_cmd_klibcld = KLIBCLD $@
+      cmd_klibcld = $(KLIBCLD) -r $(KLIBCLDFLAGS) \
+                                $(EXTRA_KLIBCLDFLAGS) $(KLIBCLDFLAGS_$(@F)) \
+                                $(filter-out FORCE,$^) -o $@
+
+
+# Link target to a new name
+# ---------------------------------------------------------------------------
+quiet_cmd_ln = LN      $@
+      cmd_ln = rm -f $@ && ln $< $@
+
+# Strip target (remove all debugging info)
+quiet_cmd_strip = STRIP   $@
+      cmd_strip = $(KLIBCSTRIP) $(KLIBCSTRIPFLAGS) $< -o $@
+
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+# Shorthand for $(Q)$(MAKE) -f scripts/Kbuild.klibc obj
+# Usage:
+# $(Q)$(MAKE) $(klibc)=dir
+klibc := -rR -f $(srctree)/scripts/Kbuild.klibc obj
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
new file mode 100644 (file)
index 0000000..a588749
--- /dev/null
@@ -0,0 +1,92 @@
+# ==========================================================================
+# Cleaning up
+# ==========================================================================
+
+src := $(obj)
+
+.PHONY: __clean
+__clean:
+
+# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+
+# Figure out what we need to build from the various variables
+# ==========================================================================
+
+subdirs := $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-n)))
+subdirs += $(patsubst %/,%,$(filter %/, $(obj-)))
+
+subdirs += $(patsubst %/,%,$(filter %/, $(klib-y)))
+subdirs += $(patsubst %/,%,$(filter %/, $(klib-)))
+
+# Subdirectories we need to descend into
+subdirs := $(addprefix $(obj)/,$(sort $(subdirs)))
+
+
+# build a list of files to remove, usually releative to the current
+# directory
+
+__clean-files  := $(extra-y) $(EXTRA_TARGETS) $(always) \
+                  $(targets) $(clean-files)             \
+                  $(host-progs)                         \
+                  $(hostprogs-y) $(hostprogs-m) $(hostprogs-) \
+                  klib.list
+
+# as clean-files is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-files   := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(__clean-files))) \
+                  $(filter /%, $(__clean-files)))
+
+# as clean-dirs is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-dirs    := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(clean-dirs)))    \
+                  $(filter /%, $(clean-dirs)))
+
+# ==========================================================================
+
+quiet_cmd_clean    = CLEAN   $(obj)
+      cmd_clean    = rm -f $(__clean-files)
+quiet_cmd_cleandir = CLEAN   $(__clean-dirs)
+      cmd_cleandir = rm -rf $(__clean-dirs)
+
+
+__clean: $(subdirs)
+ifneq ($(strip $(__clean-files)),)
+       +$(call cmd,clean)
+endif
+ifneq ($(strip $(__clean-dirs)),)
+       +$(call cmd,cleandir)
+endif
+ifneq ($(strip $(clean-rule)),)
+       +$(clean-rule)
+endif
+       @:
+
+
+# ===========================================================================
+# Generic stuff
+# ===========================================================================
+
+# Descending
+# ---------------------------------------------------------------------------
+
+.PHONY: $(subdirs)
+$(subdirs):
+       $(Q)$(MAKE) $(clean)=$@
+
+# If quiet is set, only print short version of command
+
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
new file mode 100644 (file)
index 0000000..6a6b949
--- /dev/null
@@ -0,0 +1,160 @@
+# ==========================================================================
+# Building binaries on the host system
+# Binaries are used during the compilation of the kernel, for example
+# to preprocess a data file.
+#
+# Both C and C++ is supported, but preferred language is C for such utilities.
+#
+# Sample syntax (see Documentation/kbuild/makefile.txt for reference)
+# hostprogs-y := bin2hex
+# Will compile bin2hex.c and create an executable named bin2hex
+#
+# hostprogs-y    := lxdialog
+# lxdialog-objs := checklist.o lxdialog.o
+# Will compile lxdialog.c and checklist.c, and then link the executable
+# lxdialog, based on checklist.o and lxdialog.o
+#
+# hostprogs-y      := qconf
+# qconf-cxxobjs   := qconf.o
+# qconf-objs      := menu.o
+# Will compile qconf as a C++ program, and menu as a C program.
+# They are linked as C++ code to the executable qconf
+
+# hostprogs-y := conf
+# conf-objs  := conf.o libkconfig.so
+# libkconfig-objs := expr.o type.o
+# Will create a shared library named libkconfig.so that consist of
+# expr.o and type.o (they are both compiled as C code and the object file
+# are made as position independent code).
+# conf.c is compiled as a c program, and conf.o is linked together with
+# libkconfig.so as the executable conf.
+# Note: Shared libraries consisting of C++ files are not supported
+
+__hostprogs := $(sort $(hostprogs-y)$(hostprogs-m))
+
+# hostprogs-y := tools/build may have been specified. Retreive directory
+obj-dirs += $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+obj-dirs := $(strip $(sort $(filter-out ./,$(obj-dirs))))
+
+
+# C code
+# Executables compiled from a single .c file
+host-csingle   := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
+
+# C executables linked based on several .o files
+host-cmulti    := $(foreach m,$(__hostprogs),\
+                  $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+
+# Object (.o) files compiled from .c files
+host-cobjs     := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
+
+# C++ code
+# C++ executables compiled from at least on .cc file
+# and zero or more .c files
+host-cxxmulti  := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
+
+# C++ Object (.o) files compiled from .cc files
+host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
+
+# Shared libaries (only .c supported)
+# Shared libraries (.so) - all .so files referenced in "xxx-objs"
+host-cshlib    := $(sort $(filter %.so, $(host-cobjs)))
+# Remove .so files from "xxx-objs"
+host-cobjs     := $(filter-out %.so,$(host-cobjs))
+
+#Object (.o) files used by the shared libaries
+host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+
+__hostprogs     := $(addprefix $(obj)/,$(__hostprogs))
+host-csingle   := $(addprefix $(obj)/,$(host-csingle))
+host-cmulti    := $(addprefix $(obj)/,$(host-cmulti))
+host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
+host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
+host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
+host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
+host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
+obj-dirs        := $(addprefix $(obj)/,$(obj-dirs))
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+# Prefix -I with $(srctree) if it is not an absolute path
+addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+# Find all -I options and call addtree
+flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   $(HOSTCFLAGS_$(*F).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) $(HOSTCXXFLAGS_$(*F).o)
+
+ifeq ($(KBUILD_SRC),)
+__hostc_flags  = $(_hostc_flags)
+__hostcxx_flags        = $(_hostcxx_flags)
+else
+__hostc_flags  = -I$(obj) $(call flags,_hostc_flags)
+__hostcxx_flags        = -I$(obj) $(call flags,_hostcxx_flags)
+endif
+
+hostc_flags    = -Wp,-MD,$(depfile) $(__hostc_flags)
+hostcxx_flags  = -Wp,-MD,$(depfile) $(__hostcxx_flags)
+
+#####
+# Compile programs on the host
+
+# Create executable from a single .c file
+# host-csingle -> Executable
+quiet_cmd_host-csingle         = HOSTCC  $@
+      cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
+               $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-csingle): %: %.c FORCE
+       $(call if_changed_dep,host-csingle)
+
+# Link an executable based on list of .o files, all plain c
+# host-cmulti -> executable
+quiet_cmd_host-cmulti  = HOSTLD  $@
+      cmd_host-cmulti  = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
+                         $(addprefix $(obj)/,$($(@F)-objs)) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cmulti)
+
+# Create .o file from a single .c file
+# host-cobjs -> .o
+quiet_cmd_host-cobjs   = HOSTCC  $@
+      cmd_host-cobjs   = $(HOSTCC) $(hostc_flags) -c -o $@ $<
+$(host-cobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cobjs)
+
+# Link an executable based on list of .o files, a mixture of .c and .cc
+# host-cxxmulti -> executable
+quiet_cmd_host-cxxmulti        = HOSTLD  $@
+      cmd_host-cxxmulti        = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
+                         $(foreach o,objs cxxobjs,\
+                         $(addprefix $(obj)/,$($(@F)-$(o)))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxmulti): %: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cxxmulti)
+
+# Create .o file from a single .cc (C++) file
+quiet_cmd_host-cxxobjs = HOSTCXX $@
+      cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
+$(host-cxxobjs): %.o: %.cc FORCE
+       $(call if_changed_dep,host-cxxobjs)
+
+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
+      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): %.o: %.c FORCE
+       $(call if_changed_dep,host-cshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib  = HOSTLLD -shared $@
+      cmd_host-cshlib  = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): %: $(host-cshobjs) FORCE
+       $(call if_changed,host-cshlib)
+
+targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs)
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
new file mode 100644 (file)
index 0000000..a776371
--- /dev/null
@@ -0,0 +1 @@
+fixdep
diff --git a/scripts/basic/Kbuild b/scripts/basic/Kbuild
new file mode 100644 (file)
index 0000000..22e09d2
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Kbuild file to build basic kbuild programs
+#
+
+hostprogs-y := fixdep
+always      := $(hostprogs-y)
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
new file mode 100644 (file)
index 0000000..fed4c7f
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ *
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes <linux/config.h> which then again
+ * includes <linux/autoconf.h>
+ *
+ * If the user re-runs make *config, linux/autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autoconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ *
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *
+ * To be exact, split-include populates a tree in include/config/,
+ * e.g. include/config/his/driver.h, which contains the #define/#undef
+ * for the CONFIG_HIS_DRIVER option.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-)
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ *
+ * So to get dependencies right, there are two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <depfile> <target> <cmdline>
+ *
+ * and will read the dependency file <depfile>
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on linux/autoconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ *
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+/*
+ * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
+ * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
+ * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
+ * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
+ * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
+ * those files will have correct dependencies.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+       exit(1);
+}
+
+static void print_cmdline(void)
+{
+       printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+static void grow_config(int len)
+{
+       while (len_config + len > size_config) {
+               if (size_config == 0)
+                       size_config = 2048;
+               str_config = realloc(str_config, size_config *= 2);
+               if (str_config == NULL)
+                       { perror("fixdep:malloc"); exit(1); }
+       }
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+static int is_defined_config(const char *name, int len)
+{
+       const char * pconfig;
+       const char * plast = str_config + len_config - len;
+       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+               if (pconfig[ -1] == '\n'
+               &&  pconfig[len] == '\n'
+               &&  !memcmp(pconfig, name, len))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+static void define_config(const char *name, int len)
+{
+       grow_config(len + 1);
+
+       memcpy(str_config+len_config, name, len);
+       len_config += len;
+       str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+static void clear_config(void)
+{
+       len_config = 0;
+       define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+static void use_config(char *m, int slen)
+{
+       char s[PATH_MAX];
+       char *p;
+
+       if (is_defined_config(m, slen))
+           return;
+
+       define_config(m, slen);
+
+       memcpy(s, m, slen); s[slen] = 0;
+
+       for (p = s; p < s + slen; p++) {
+               if (*p == '_')
+                       *p = '/';
+               else
+                       *p = tolower((int)*p);
+       }
+       printf("    $(wildcard include/config/%s.h) \\\n", s);
+}
+
+static void parse_config_file(char *map, size_t len)
+{
+       int *end = (int *) (map + len);
+       /* start at +1, so that p can never be < map */
+       int *m   = (int *) map + 1;
+       char *p, *q;
+
+       for (; m < end; m++) {
+               if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+               if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+               if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+               if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+               continue;
+       conf:
+               if (p > map + len - 7)
+                       continue;
+               if (memcmp(p, "CONFIG_", 7))
+                       continue;
+               for (q = p + 7; q < map + len; q++) {
+                       if (!(isalnum(*q) || *q == '_'))
+                               goto found;
+               }
+               continue;
+
+       found:
+               use_config(p+7, q-p-7);
+       }
+}
+
+/* test is s ends in sub */
+static int strrcmp(char *s, char *sub)
+{
+       int slen = strlen(s);
+       int sublen = strlen(sub);
+
+       if (sublen > slen)
+               return 1;
+
+       return memcmp(s + slen - sublen, sub, sublen);
+}
+
+static void do_config_file(char *filename)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(filename);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_config_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+static void parse_dep_file(void *map, size_t len)
+{
+       char *m = map;
+       char *end = m + len;
+       char *p;
+       char s[PATH_MAX];
+
+       p = strchr(m, ':');
+       if (!p) {
+               fprintf(stderr, "fixdep: parse error\n");
+               exit(1);
+       }
+       memcpy(s, m, p-m); s[p-m] = 0;
+       printf("deps_%s := \\\n", target);
+       m = p+1;
+
+       clear_config();
+
+       while (m < end) {
+               while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+                       m++;
+               p = m;
+               while (p < end && *p != ' ') p++;
+               if (p == end) {
+                       do p--; while (!isalnum(*p));
+                       p++;
+               }
+               memcpy(s, m, p-m); s[p-m] = 0;
+               if (strrcmp(s, "include/linux/autoconf.h") &&
+                   strrcmp(s, "arch/um/include/uml-config.h") &&
+                   strrcmp(s, ".ver")) {
+                       printf("  %s \\\n", s);
+                       do_config_file(s);
+               }
+               m = p + 1;
+       }
+       printf("\n%s: $(deps_%s)\n\n", target, target);
+       printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(depfile, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(depfile);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               fprintf(stderr,"fixdep: %s is empty\n",depfile);
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_dep_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+static void traps(void)
+{
+       static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
+       int *p = (int *)test;
+
+       if (*p != INT_CONF) {
+               fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
+                       *p);
+               exit(2);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       traps();
+
+       if (argc != 4)
+               usage();
+
+       depfile = argv[1];
+       target = argv[2];
+       cmdline = argv[3];
+
+       print_cmdline();
+       print_deps();
+
+       return 0;
+}
diff --git a/usr/.gitignore b/usr/.gitignore
new file mode 100644 (file)
index 0000000..77534ee
--- /dev/null
@@ -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 (file)
index 0000000..890811c
--- /dev/null
@@ -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 (file)
index 0000000..480952f
--- /dev/null
@@ -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 (file)
index 0000000..3a98c1f
--- /dev/null
@@ -0,0 +1,96 @@
+#
+# 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
+
+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 := sh
+
+# The shared binary
+shared-y    := sh.shared
+sh.shared-y := $(sh-y)
+
+# For cleaning
+targets := sh sh.g sh.shared sh.shared.g $(gen-o-files)
+
+# explicit dependency for all generated files
+$(addprefix $(obj)/, $(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):
+
+# Targets to install
+install-y := sh.shared
diff --git a/usr/dash/README.dash b/usr/dash/README.dash
new file mode 100644 (file)
index 0000000..3846f0b
--- /dev/null
@@ -0,0 +1,30 @@
+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.
+
+HOWTO sync branch:
+1) Generate patch and fix up their path
+
+ git format-patch --subject-prefix=klibc -N <changeset>..
+
+Path fixup:
+ perl -i -pe 's#^([-+]{3} [ab]/)src/#$1#g' 00*patch
+
+2) Import patches on by one
+ git am --directory="usr/dash" --exclude="usr/dash/configure.ac" \
+       --exclude="usr/dash/ChangeLog" --exclude="usr/dash/dash.1" \
+       --exclude="usr/dash/Makefile.am" --exclude="usr/dash/mksignames.c" \
+       --whitespace=fix -k -i -s ../dash/000X-foo.patch
+
+The only changes made are the addition of config.h, Kbuild usage,
+the omition of Changelog and manpage and automatic whitespace fixups.
+
+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 (file)
index 0000000..056e79b
--- /dev/null
@@ -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 (file)
index 0000000..daeacbb
--- /dev/null
@@ -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 (file)
index 0000000..fb841d6
--- /dev/null
@@ -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 (file)
index 0000000..1a087c3
--- /dev/null
@@ -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 (file)
index 0000000..ff34d52
--- /dev/null
@@ -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 (file)
index 0000000..ec5b5b2
--- /dev/null
@@ -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 (file)
index 0000000..f5ac06f
--- /dev/null
@@ -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 (file)
index 0000000..fbc7fb4
--- /dev/null
@@ -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 (file)
index 0000000..b1265a5
--- /dev/null
@@ -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 (file)
index 0000000..b32b54f
--- /dev/null
@@ -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 (file)
index 0000000..42435fb
--- /dev/null
@@ -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 (file)
index 0000000..90135e1
--- /dev/null
@@ -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 (file)
index 0000000..e116963
--- /dev/null
@@ -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 (file)
index 0000000..89c6c30
--- /dev/null
@@ -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 (file)
index 0000000..8763161
--- /dev/null
@@ -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 (file)
index 0000000..35230c7
--- /dev/null
@@ -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. */
+/* #undef HAVE_SYSCONF */
+
+/* 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 (file)
index 0000000..9d31989
--- /dev/null
@@ -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 (file)
index 0000000..f91d11d
--- /dev/null
@@ -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 (file)
index 0000000..ae83508
--- /dev/null
@@ -0,0 +1,1091 @@
+/*-
+ * 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" + (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 (file)
index 0000000..5ccfa9f
--- /dev/null
@@ -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 (file)
index 0000000..79e2007
--- /dev/null
@@ -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 (file)
index 0000000..9ccb305
--- /dev/null
@@ -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 (file)
index 0000000..355e924
--- /dev/null
@@ -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 (file)
index 0000000..9cf1276
--- /dev/null
@@ -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 (file)
index 0000000..91a67c5
--- /dev/null
@@ -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 (file)
index 0000000..7d840eb
--- /dev/null
@@ -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 (file)
index 0000000..c5df95f
--- /dev/null
@@ -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 (file)
index 0000000..215e535
--- /dev/null
@@ -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 (file)
index 0000000..ec0e7e5
--- /dev/null
@@ -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 (file)
index 0000000..3b1ab46
--- /dev/null
@@ -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 (file)
index 0000000..483d358
--- /dev/null
@@ -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 (file)
index 0000000..4484467
--- /dev/null
@@ -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 (executable)
index 0000000..e6797de
--- /dev/null
@@ -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 (file)
index 0000000..f7d175f
--- /dev/null
@@ -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 (file)
index 0000000..5f49713
--- /dev/null
@@ -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 (file)
index 0000000..b27d629
--- /dev/null
@@ -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 (file)
index 0000000..e026e86
--- /dev/null
@@ -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 (file)
index 0000000..d31c45b
--- /dev/null
@@ -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 (file)
index 0000000..50a7797
--- /dev/null
@@ -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 (file)
index 0000000..009bbfe
--- /dev/null
@@ -0,0 +1,1503 @@
+/*-
+ * 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, 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 = "\"}" + !(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 (file)
index 0000000..953ee87
--- /dev/null
@@ -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 (file)
index 0000000..b1ca07a
--- /dev/null
@@ -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 (file)
index 0000000..02e07f7
--- /dev/null
@@ -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 (file)
index 0000000..3c6b21d
--- /dev/null
@@ -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 (file)
index 0000000..7df3c44
--- /dev/null
@@ -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 (file)
index 0000000..19e4983
--- /dev/null
@@ -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 (file)
index 0000000..d8e4413
--- /dev/null
@@ -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 (file)
index 0000000..4b5be46
--- /dev/null
@@ -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 (file)
index 0000000..09282be
--- /dev/null
@@ -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 (file)
index 0000000..dd9a8d1
--- /dev/null
@@ -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 (file)
index 0000000..f562ae2
--- /dev/null
@@ -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=tempfile
+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_COLLATE=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 (file)
index 0000000..9714bee
--- /dev/null
@@ -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 (file)
index 0000000..1903a60
--- /dev/null
@@ -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 (file)
index 0000000..a23c18c
--- /dev/null
@@ -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 (file)
index 0000000..8fbcef1
--- /dev/null
@@ -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 (file)
index 0000000..5888088
--- /dev/null
@@ -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 (file)
index 0000000..0106bd2
--- /dev/null
@@ -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 (file)
index 0000000..083ea98
--- /dev/null
@@ -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 (file)
index 0000000..9125bc7
--- /dev/null
@@ -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 (file)
index 0000000..ceaf478
--- /dev/null
@@ -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 (file)
index 0000000..6f381e6
--- /dev/null
@@ -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 (file)
index 0000000..975fe33
--- /dev/null
@@ -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 (file)
index 0000000..f62e7ea
--- /dev/null
@@ -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 (file)
index 0000000..f853e9d
--- /dev/null
@@ -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 (file)
index 0000000..6e076a5
--- /dev/null
@@ -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 (file)
index 0000000..e6caed6
--- /dev/null
@@ -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 (file)
index 0000000..f96a76b
--- /dev/null
@@ -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 (file)
index 0000000..8e56995
--- /dev/null
@@ -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 (file)
index 0000000..ff5881a
--- /dev/null
@@ -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 (file)
index 0000000..98edc8b
--- /dev/null
@@ -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 (file)
index 0000000..4a049e9
--- /dev/null
@@ -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 (file)
index 0000000..d0ccac7
--- /dev/null
@@ -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 (file)
index 0000000..aa1df8a
--- /dev/null
@@ -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 (file)
index 0000000..c8424f7
--- /dev/null
@@ -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 (file)
index 0000000..1e2a867
--- /dev/null
@@ -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 (file)
index 0000000..6590be1
--- /dev/null
@@ -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 (file)
index 0000000..dc90249
--- /dev/null
@@ -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 (file)
index 0000000..1a06a3c
--- /dev/null
@@ -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 (file)
index 0000000..b665e3f
--- /dev/null
@@ -0,0 +1,3 @@
+gunzip
+gzip
+zcat
diff --git a/usr/gzip/COPYING b/usr/gzip/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
@@ -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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+       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 (file)
index 0000000..9bbf0a4
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# 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 gunzip zcat
diff --git a/usr/gzip/README b/usr/gzip/README
new file mode 100644 (file)
index 0000000..fdd7311
--- /dev/null
@@ -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 (file)
index 0000000..4707a08
--- /dev/null
@@ -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 (file)
index 0000000..1db44fd
--- /dev/null
@@ -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 (file)
index 0000000..ab73de0
--- /dev/null
@@ -0,0 +1,1212 @@
+/* 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) */
+#ifndef decompress
+int decompress;       /* decompress (-d) */
+#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.
+     */
+#ifndef decompress
+    if (  strncmp(progname, "un",  2) == 0     /* ungzip, uncompress */
+       || strncmp(progname, "gun", 3) == 0) {  /* gunzip */
+       decompress = 1;
+    }
+#endif
+    if (strequ(progname+1, "cat")       /* zcat, pcat, gcat */
+       || strequ(progname, "gzcat")) {    /* gzcat */
+#ifndef decompress
+       decompress = 1;
+#endif
+       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':
+#ifndef decompress
+           decompress = 1;
+#endif
+           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;
+#ifndef decompress
+           decompress = 1;
+#endif
+           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 */
+
+    /* 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 (file)
index 0000000..7cd2fbd
--- /dev/null
@@ -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 (file)
index 0000000..a540538
--- /dev/null
@@ -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 (file)
index 0000000..736020b
--- /dev/null
@@ -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 (file)
index 0000000..849e589
--- /dev/null
@@ -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 (file)
index 0000000..75efc97
--- /dev/null
@@ -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 (file)
index 0000000..c8e14a3
--- /dev/null
@@ -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 (file)
index 0000000..22ff6e5
--- /dev/null
@@ -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 (file)
index 0000000..d0394c2
--- /dev/null
@@ -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 (file)
index 0000000..0032724
--- /dev/null
@@ -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 (file)
index 0000000..91ef4c0
--- /dev/null
@@ -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 (file)
index 0000000..272fee0
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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
+
+#define _KLIBC_USE_RT_SIG 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 (file)
index 0000000..47638b3
--- /dev/null
@@ -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 (file)
index 0000000..2193a35
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * arch/alpha/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/alpha/klibc/archstat.h b/usr/include/arch/alpha/klibc/archstat.h
new file mode 100644 (file)
index 0000000..66e29be
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned long   st_ino;
+       __stdev64       (st_rdev);
+       long            st_size;
+       unsigned long   st_blocks;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_blksize;
+       unsigned int    st_nlink;
+       unsigned int    __pad0;
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       long            __unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/alpha/machine/asm.h b/usr/include/arch/alpha/machine/asm.h
new file mode 100644 (file)
index 0000000..c2ae4ed
--- /dev/null
@@ -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 (file)
index 0000000..cfe847a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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
+
+/* Use rt_* signals */
+#define _KLIBC_USE_RT_SIG 1
+
+#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 (file)
index 0000000..88db8a1
--- /dev/null
@@ -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 (file)
index 0000000..7189da7
--- /dev/null
@@ -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/archstat.h b/usr/include/arch/arm/klibc/archstat.h
new file mode 100644 (file)
index 0000000..95bbc9e
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ * Note: The kernel zero's the padded region because glibc might read them
+ * in the hope that the kernel has stretched to using larger sizes.
+ */
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad0[4];
+
+       unsigned long   __st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long long  st_blocks;  /* Number 512-byte blocks allocated. */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/arm/klibc/asmmacros.h b/usr/include/arch/arm/klibc/asmmacros.h
new file mode 100644 (file)
index 0000000..a6810ce
--- /dev/null
@@ -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 (file)
index 0000000..5e2004b
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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
+
+/* Use rt_* signals */
+#define _KLIBC_USE_RT_SIG 1
+#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 (file)
index 0000000..edc3312
--- /dev/null
@@ -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 (file)
index 0000000..94e6bc8
--- /dev/null
@@ -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/arm64/klibc/archstat.h b/usr/include/arch/arm64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..f5bfa80
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);       /* Device */
+       unsigned long   st_ino;         /* File serial number */
+       unsigned int    st_mode;        /* File mode */
+       unsigned int    st_nlink;       /* Link count */
+       unsigned int    st_uid;         /* User ID of the file's owner */
+       unsigned int    st_gid;         /* Group ID of the file's group */
+       __stdev64       (st_rdev);      /* Device number, if device */
+       unsigned long   __pad1;
+       long            st_size;        /* Size of file, in bytes */
+       int             st_blksize;     /* Optimal block size for I/O */
+       int             __pad2;
+       long            st_blocks;      /* Number 512-byte blocks allocated */
+       struct timespec st_atim;        /* Time of last access */
+       struct timespec st_mtim;        /* Time of last modification */
+       struct timespec st_ctim;        /* Time of last status change */
+       unsigned int    __unused4;
+       unsigned int    __unused5;
+};
+
+#endif
diff --git a/usr/include/arch/cris/klibc/archconfig.h b/usr/include/arch/cris/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..0206078
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * include/arch/cris/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
+
+/* cris uses 13 as the page shift factor for sys_mmap2 */
+#define _KLIBC_MMAP2_SHIFT     13
+
+#endif                         /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/cris/klibc/archsetjmp.h b/usr/include/arch/cris/klibc/archsetjmp.h
new file mode 100644 (file)
index 0000000..d345ccb
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arch/cris/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+       unsigned long __r0;
+       unsigned long __r1;
+       unsigned long __r2;
+       unsigned long __r3;
+       unsigned long __r4;
+       unsigned long __r5;
+       unsigned long __r6;
+       unsigned long __r7;
+       unsigned long __r8;
+       unsigned long __sp;
+       unsigned long __srp;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif                         /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/cris/klibc/archsignal.h b/usr/include/arch/cris/klibc/archsignal.h
new file mode 100644 (file)
index 0000000..7fa7454
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * arch/cris/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/cris/klibc/archstat.h b/usr/include/arch/cris/klibc/archstat.h
new file mode 100644 (file)
index 0000000..09d3ade
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad0[4];
+
+       unsigned long   __st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
+       unsigned long   __pad4;         /* future possible st_blocks high bits */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/i386/klibc/archconfig.h b/usr/include/arch/i386/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..d8db763
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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
+
+/* The i386 <asm/signal.h> is still not clean enough for this... */
+#define _KLIBC_USE_RT_SIG 0
+
+/* We have __libc_arch_init() */
+#define _KLIBC_HAS_ARCHINIT 1
+
+#endif                         /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/i386/klibc/archsetjmp.h b/usr/include/arch/i386/klibc/archsetjmp.h
new file mode 100644 (file)
index 0000000..ea1ba3d
--- /dev/null
@@ -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 (file)
index 0000000..c83fc8f
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+/* The in-kernel headers for i386 got clean up, use them. */
+
+#include <linux/signal.h>
+
+#endif
diff --git a/usr/include/arch/i386/klibc/archstat.h b/usr/include/arch/i386/klibc/archstat.h
new file mode 100644 (file)
index 0000000..c00f955
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad0[4];
+
+       unsigned long   __st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long long st_blocks;   /* Number 512-byte blocks allocated. */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/i386/klibc/diverr.h b/usr/include/arch/i386/klibc/diverr.h
new file mode 100644 (file)
index 0000000..fa238ac
--- /dev/null
@@ -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 (file)
index 0000000..cf31b97
--- /dev/null
@@ -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 (file)
index 0000000..c4651cd
--- /dev/null
@@ -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 (file)
index 0000000..adbd1ee
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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
+
+#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 (file)
index 0000000..43564ee
--- /dev/null
@@ -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 (file)
index 0000000..fbc961b
--- /dev/null
@@ -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;
+       sigset_t sa_mask;
+       int sa_flags;
+};
+
+#define sa_handler      _u._sa_handler
+#define sa_sigaction    _u._sa_sigaction
+
+#endif
diff --git a/usr/include/arch/ia64/klibc/archstat.h b/usr/include/arch/ia64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..ff38e41
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned long   st_ino;
+       unsigned long   st_nlink;
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    __pad0;
+       __stdev64       (st_rdev);
+       unsigned long   st_size;
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       unsigned long   st_blksize;
+       long            st_blocks;
+       unsigned long   __unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/m32r/klibc/archconfig.h b/usr/include/arch/m32r/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..9489877
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * include/arch/m32r/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/m32r/klibc/archsetjmp.h b/usr/include/arch/m32r/klibc/archsetjmp.h
new file mode 100644 (file)
index 0000000..d82df9c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * arch/m32r/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;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif                         /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/m32r/klibc/archsignal.h b/usr/include/arch/m32r/klibc/archsignal.h
new file mode 100644 (file)
index 0000000..b753026
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * arch/m32r/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/m32r/klibc/archstat.h b/usr/include/arch/m32r/klibc/archstat.h
new file mode 100644 (file)
index 0000000..09d3ade
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad0[4];
+
+       unsigned long   __st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
+       unsigned long   __pad4;         /* future possible st_blocks high bits */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/m68k/klibc/archconfig.h b/usr/include/arch/m68k/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..10ef62e
--- /dev/null
@@ -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 (file)
index 0000000..e85c810
--- /dev/null
@@ -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 (file)
index 0000000..bf7912a
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * arch/m68k/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/m68k/klibc/archstat.h b/usr/include/arch/m68k/klibc/archstat.h
new file mode 100644 (file)
index 0000000..dce25f9
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad1[2];
+
+       unsigned long   __st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[2];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long long      st_blocks;      /* Number 512-byte blocks allocated. */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/mips/klibc/archconfig.h b/usr/include/arch/mips/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..9c21efc
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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
+
+/* We can use RT signals on MIPS */
+#define _KLIBC_USE_RT_SIG 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 (file)
index 0000000..2e57116
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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_SYNC         0x0010
+#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_DIRECT       0x8000
+#define O_DIRECTORY    0x10000
+#define O_NOFOLLOW     0x20000
+#define O_NOATIME      0x40000
+#define O_CLOEXEC      0x80000
+
+#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 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 (file)
index 0000000..1fbe83e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+       unsigned long __f20;
+       unsigned long __f21;
+       unsigned long __f22;
+       unsigned long __f23;
+       unsigned long __f24;
+       unsigned long __f25;
+       unsigned long __f26;
+       unsigned long __f27;
+       unsigned long __f28;
+       unsigned long __f29;
+       unsigned long __f30;
+       unsigned long __f31;
+       unsigned long __fcr31;
+       unsigned long __unused;
+} __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 (file)
index 0000000..b9ca756
--- /dev/null
@@ -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 (file)
index 0000000..d6daf1b
--- /dev/null
@@ -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/klibc/archstat.h b/usr/include/arch/mips/klibc/archstat.h
new file mode 100644 (file)
index 0000000..b06686f
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <sys/types.h>
+
+#define _STATBUF_ST_NSEC
+
+/*
+ * This matches struct stat64 in glibc2.1, hence the absolutely insane
+ * amounts of padding around dev_t's.  The memory layout is the same as of
+ * struct stat of the 64-bit kernel, which makes this one of the sanest
+ * 32-bit struct stats.
+ */
+
+struct stat {
+       unsigned int    st_dev;
+       unsigned long   st_pad0[3];     /* Reserved for st_dev expansion  */
+
+       unsigned long long      st_ino;
+
+       mode_t          st_mode;
+       __u32           st_nlink;
+
+       uid_t           st_uid;
+       gid_t           st_gid;
+
+       unsigned int    st_rdev;
+       unsigned long   st_pad1[3];     /* Reserved for st_rdev expansion  */
+
+       long long       st_size;
+
+       struct timespec         st_atim;
+       struct timespec         st_mtim;
+       struct timespec         st_ctim;
+
+       unsigned long   st_blksize;
+       unsigned long   st_pad2;
+
+       long long       st_blocks;
+};
+
+#endif
diff --git a/usr/include/arch/mips/machine/asm.h b/usr/include/arch/mips/machine/asm.h
new file mode 100644 (file)
index 0000000..0b8cece
--- /dev/null
@@ -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 (file)
index 0000000..fba8ae8
--- /dev/null
@@ -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 (file)
index 0000000..b5f530b
--- /dev/null
@@ -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 (file)
index 0000000..4d856a5
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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
+
+/* We can use RT signals on MIPS */
+#define _KLIBC_USE_RT_SIG 1
+
+#endif                         /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/mips64/klibc/archsignal.h b/usr/include/arch/mips64/klibc/archsignal.h
new file mode 100644 (file)
index 0000000..f350af9
--- /dev/null
@@ -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 (file)
index 0000000..6c3947d
--- /dev/null
@@ -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/klibc/archstat.h b/usr/include/arch/mips64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..2dbb907
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <sys/types.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       unsigned int            st_dev;
+       unsigned int            st_pad0[3]; /* Reserved for st_dev expansion */
+
+       unsigned long           st_ino;
+
+       mode_t                  st_mode;
+       __u32                   st_nlink;
+
+       uid_t                   st_uid;
+       gid_t                   st_gid;
+
+       unsigned int            st_rdev;
+       unsigned int            st_pad1[3]; /* Reserved for st_rdev expansion */
+
+       off_t                   st_size;
+
+       struct timespec         st_atim;
+       struct timespec         st_mtim;
+       struct timespec         st_ctim;
+
+       unsigned int            st_blksize;
+       unsigned int            st_pad2;
+
+       unsigned long           st_blocks;
+};
+
+#endif
diff --git a/usr/include/arch/parisc/klibc/archconfig.h b/usr/include/arch/parisc/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..f8ba9e2
--- /dev/null
@@ -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 (file)
index 0000000..05e943e
--- /dev/null
@@ -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 (file)
index 0000000..256aeea
--- /dev/null
@@ -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/parisc/klibc/archstat.h b/usr/include/arch/parisc/klibc/archstat.h
new file mode 100644 (file)
index 0000000..0b8ef8d
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64               (st_dev);
+       unsigned int            __pad1;
+
+       unsigned int            __st_ino;       /* Not actually filled in */
+       unsigned int            st_mode;
+       unsigned int            st_nlink;
+       unsigned int            st_uid;
+       unsigned int            st_gid;
+       __stdev64               (st_rdev);
+       unsigned int            __pad2;
+       signed long long        st_size;
+       signed int              st_blksize;
+
+       signed long long        st_blocks;
+       struct timespec         st_atim;
+       struct timespec         st_mtim;
+       struct timespec         st_ctim;
+       unsigned long long      st_ino;
+};
+
+#endif
diff --git a/usr/include/arch/ppc/klibc/archconfig.h b/usr/include/arch/ppc/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..61c3657
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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
+
+#define _KLIBC_USE_RT_SIG 1
+
+#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 (file)
index 0000000..4be9ed6
--- /dev/null
@@ -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 (file)
index 0000000..9c3ac92
--- /dev/null
@@ -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/ppc/klibc/archstat.h b/usr/include/arch/ppc/klibc/archstat.h
new file mode 100644 (file)
index 0000000..9e31f4a
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1.
+ */
+struct stat {
+       __stdev64 (st_dev);             /* Device. */
+       unsigned long long st_ino;      /* File serial number.  */
+       unsigned int st_mode;           /* File mode.  */
+       unsigned int st_nlink;          /* Link count.  */
+       unsigned int st_uid;            /* User ID of the file's owner.  */
+       unsigned int st_gid;            /* Group ID of the file's group. */
+       __stdev64 (st_rdev);            /* Device number, if device.  */
+       unsigned short int __pad2;
+       long long st_size;              /* Size of file, in bytes.  */
+       long st_blksize;                /* Optimal block size for I/O.  */
+
+       long long st_blocks;            /* Number 512-byte blocks allocated. */
+       struct timespec st_atim;        /* Time of last access.  */
+       struct timespec st_mtim;        /* Time of last modification.  */
+       struct timespec st_ctim;        /* Time of last status change.  */
+       unsigned long int __unused4;
+       unsigned long int __unused5;
+};
+
+#endif
diff --git a/usr/include/arch/ppc64/klibc/archconfig.h b/usr/include/arch/ppc64/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..27c5630
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * 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
+
+#define _KLIBC_USE_RT_SIG 1
+
+#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 (file)
index 0000000..d227728
--- /dev/null
@@ -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 (file)
index 0000000..2c4cef0
--- /dev/null
@@ -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/ppc64/klibc/archstat.h b/usr/include/arch/ppc64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..918d810
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+       ino_t           st_ino;
+       unsigned long   st_nlink;
+       mode_t          st_mode;
+       uid_t           st_uid;
+       gid_t           st_gid;
+       __stdev64       (st_rdev);
+       off_t           st_size;
+       unsigned long   st_blksize;
+       unsigned long   st_blocks;
+       struct timespec st_atim;        /* Time of last access.  */
+       struct timespec st_mtim;        /* Time of last modification.  */
+       struct timespec st_ctim;        /* Time of last status change.  */
+       unsigned long   __unused4;
+       unsigned long   __unused5;
+       unsigned long   __unused6;
+};
+
+#endif
diff --git a/usr/include/arch/s390/klibc/archconfig.h b/usr/include/arch/s390/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..d7a71a4
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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
+
+#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 (file)
index 0000000..728780a
--- /dev/null
@@ -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[4]; /* fp registers f1, f3, f5, f7 */
+};
+
+#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 (file)
index 0000000..a16b977
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * arch/s390/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/s390/klibc/archstat.h b/usr/include/arch/s390/klibc/archstat.h
new file mode 100644 (file)
index 0000000..ca4c822
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+#ifndef __s390x__
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned int    __pad1;
+#define STAT64_HAS_BROKEN_ST_INO       1
+       unsigned long   __st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+       __stdev64       (st_rdev);
+       unsigned int    __pad3;
+       long long       st_size;
+       unsigned long   st_blksize;
+       unsigned char   __pad4[4];
+       unsigned long   __pad5;     /* future possible st_blocks high bits */
+       unsigned long   st_blocks;  /* Number 512-byte blocks allocated. */
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       unsigned long long      st_ino;
+};
+
+#else /* __s390x__ */
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned long   st_ino;
+       unsigned long   st_nlink;
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    __pad1;
+       __stdev64       (st_rdev);
+       unsigned long   st_size;
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       unsigned long   st_blksize;
+       long            st_blocks;
+       unsigned long   __unused[3];
+};
+
+#endif /* __s390x__ */
+#endif
diff --git a/usr/include/arch/sh/klibc/archconfig.h b/usr/include/arch/sh/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..923c563
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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
+
+/* Use rt_* signals */
+#define _KLIBC_USE_RT_SIG 1
+
+#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 (file)
index 0000000..bb97167
--- /dev/null
@@ -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 (file)
index 0000000..8e48e51
--- /dev/null
@@ -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/sh/klibc/archstat.h b/usr/include/arch/sh/klibc/archstat.h
new file mode 100644 (file)
index 0000000..4f39181
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat {
+       __stdev64       (st_dev);
+       unsigned char   __pad0[4];
+
+       unsigned long   st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned long   st_uid;
+       unsigned long   st_gid;
+
+       __stdev64       (st_rdev);
+       unsigned char   __pad3[4];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long long st_blocks;
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long   __unused1;
+       unsigned long   __unused2;
+};
+
+#endif
diff --git a/usr/include/arch/sparc/klibc/archconfig.h b/usr/include/arch/sparc/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..70d5ef0
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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_USE_RT_SIG 1    /* Use rt_* signals */
+#define _KLIBC_SYS_SOCKETCALL 1 /* Use sys_socketcall unconditionally */
+
+#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 (file)
index 0000000..9b4d6a2
--- /dev/null
@@ -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 (file)
index 0000000..b0de544
--- /dev/null
@@ -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/klibc/archstat.h b/usr/include/arch/sparc/klibc/archstat.h
new file mode 100644 (file)
index 0000000..203d40b
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+
+       unsigned long long st_ino;
+
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+
+       __stdev64       (st_rdev);
+
+       unsigned char   __pad3[8];
+
+       long long       st_size;
+       unsigned int    st_blksize;
+
+       unsigned char   __pad4[8];
+       unsigned int    st_blocks;
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned int    __unused4;
+       unsigned int    __unused5;
+};
+
+#endif
diff --git a/usr/include/arch/sparc/machine/asm.h b/usr/include/arch/sparc/machine/asm.h
new file mode 100644 (file)
index 0000000..04fe9b1
--- /dev/null
@@ -0,0 +1,191 @@
+/*     $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
+#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
+#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 PICCY_OFFSET(var,dest,tmp)
+#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 (file)
index 0000000..6fb9c45
--- /dev/null
@@ -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 (file)
index 0000000..5c378c5
--- /dev/null
@@ -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 (file)
index 0000000..794d15b
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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_USE_RT_SIG 1    /* Use rt_* signals */
+#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 (file)
index 0000000..9e825bd
--- /dev/null
@@ -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 (file)
index 0000000..bb0a5ce
--- /dev/null
@@ -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/klibc/archstat.h b/usr/include/arch/sparc64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..56fb2a4
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned long   st_ino;
+       unsigned long   st_nlink;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    __pad0;
+
+       __stdev64 (st_rdev);
+       long            st_size;
+       long            st_blksize;
+       long            st_blocks;
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+
+       unsigned long __unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/x86_64/klibc/archconfig.h b/usr/include/arch/x86_64/klibc/archconfig.h
new file mode 100644 (file)
index 0000000..b8a2a6d
--- /dev/null
@@ -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 (file)
index 0000000..454fc60
--- /dev/null
@@ -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 (file)
index 0000000..6c8ec77
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/x86_64/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* The x86-64 headers defines NSIG 32, but it's actually 64 */
+#undef  _NSIG
+#undef  NSIG
+#define _NSIG 64
+#define NSIG  _NSIG
+
+#endif
diff --git a/usr/include/arch/x86_64/klibc/archstat.h b/usr/include/arch/x86_64/klibc/archstat.h
new file mode 100644 (file)
index 0000000..de168ac
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+       __stdev64       (st_dev);
+       unsigned long   st_ino;
+       unsigned long   st_nlink;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    __pad0;
+       __stdev64       (st_rdev);
+       long            st_size;
+       long            st_blksize;
+       long            st_blocks;      /* Number 512-byte blocks allocated. */
+
+       struct timespec st_atim;
+       struct timespec st_mtim;
+       struct timespec st_ctim;
+       long            __unused[3];
+};
+
+#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 (file)
index 0000000..19ea1fc
--- /dev/null
@@ -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 (file)
index 0000000..8532f67
--- /dev/null
@@ -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 (file)
index 0000000..9091733
--- /dev/null
@@ -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 (file)
index 0000000..06cc885
--- /dev/null
@@ -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 (file)
index 0000000..8eb97d6
--- /dev/null
@@ -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 (file)
index 0000000..8e444b6
--- /dev/null
@@ -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 (file)
index 0000000..7db63bd
--- /dev/null
@@ -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 (file)
index 0000000..d85094d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+#endif                         /* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/bits64/bitsize.h b/usr/include/bits64/bitsize.h
new file mode 100644 (file)
index 0000000..54696fd
--- /dev/null
@@ -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 (file)
index 0000000..f5bbf83
--- /dev/null
@@ -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 (file)
index 0000000..988e639
--- /dev/null
@@ -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 (file)
index 0000000..24e8eb6
--- /dev/null
@@ -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 (file)
index 0000000..805d5b8
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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
+
+#endif                         /* _BITSIZE_STDINTLIMITS_H */
diff --git a/usr/include/byteswap.h b/usr/include/byteswap.h
new file mode 100644 (file)
index 0000000..6f41a28
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * byteswap.h
+ */
+
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+#include <klibc/compiler.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 (file)
index 0000000..14a2f2d
--- /dev/null
@@ -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 (file)
index 0000000..43df503
--- /dev/null
@@ -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 (file)
index 0000000..c543a81
--- /dev/null
@@ -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 (file)
index 0000000..a6cd6d9
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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
+
+#endif                         /* _ENDIAN_H */
diff --git a/usr/include/errno.h b/usr/include/errno.h
new file mode 100644 (file)
index 0000000..d8e20bd
--- /dev/null
@@ -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 (file)
index 0000000..bbd6917
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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>
+#endif
+#include <linux/fcntl.h>
+
+/* This is ugly, but "struct flock" has actually been defined with
+   a long off_t, so it's really "struct flock64".  It just happens
+   to work.  Gag.  Barf.
+
+   This happens to work on all 32-bit architectures except MIPS. */
+
+#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
+
+/* 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 (file)
index 0000000..0d88140
--- /dev/null
@@ -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 (file)
index 0000000..71c41cd
--- /dev/null
@@ -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 (file)
index 0000000..77ce399
--- /dev/null
@@ -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 (file)
index 0000000..29311fe
--- /dev/null
@@ -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 (file)
index 0000000..ff5a006
--- /dev/null
@@ -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 (file)
index 0000000..e70887e
--- /dev/null
@@ -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 (file)
index 0000000..99563de
--- /dev/null
@@ -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 <klibc/compiler.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 (file)
index 0000000..7d7c7b8
--- /dev/null
@@ -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 (file)
index 0000000..e8ffe25
--- /dev/null
@@ -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/stathelp.h b/usr/include/klibc/stathelp.h
new file mode 100644 (file)
index 0000000..9520dad
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * stathelp.h
+ *
+ * Helper macros for <klibc/archstat.h>
+ */
+
+#ifndef _KLIBC_STATHELP_H
+#define _KLIBC_STATHELP_H
+
+#include <klibc/endian.h>
+
+/*
+ * Most architectures have a 64-bit field for st_dev and st_rdev,
+ * but dev_t is 32 bits (uint32_t == unsigned int), so make a
+ * macro we can use across all architectures.
+ */
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define __stdev64(x)  unsigned int __##x, x;
+#else
+# define __stdev64(x)  unsigned int x, __##x;
+#endif
+
+#endif                         /* _KLIBC_STATHELP_H */
diff --git a/usr/include/klibc/sysconfig.h b/usr/include/klibc/sysconfig.h
new file mode 100644 (file)
index 0000000..ab947c0
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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_USE_RT_SIG:
+ *
+ *      Indicates that this architecture should use the rt_sig*()
+ *      family of system calls, even if the older system calls are
+ *      provided.  This requires that <asm/signal.h> is correct for
+ *      using with the rt_sig*() system calls.  This is the default if
+ *      the older system calls are undefined in <asm/unistd.h>.
+ *
+ */
+#ifndef _KLIBC_USE_RT_SIG
+# ifdef __NR_sigaction
+#  define _KLIBC_USE_RT_SIG 0
+# else
+#  define _KLIBC_USE_RT_SIG 1
+# endif
+#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.
+ */
+#ifndef _KLIBC_NEEDS_SA_RESTORER
+# define _KLIBC_NEEDS_SA_RESTORER 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 uses __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 (file)
index 0000000..464420a
--- /dev/null
@@ -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 (file)
index 0000000..eb5fe34
--- /dev/null
@@ -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 (file)
index 0000000..104f35e
--- /dev/null
@@ -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 (file)
index 0000000..116a176
--- /dev/null
@@ -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 (file)
index 0000000..6261eeb
--- /dev/null
@@ -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 (file)
index 0000000..b5e8e0e
--- /dev/null
@@ -0,0 +1 @@
+#include <linux/if_packet.h>
diff --git a/usr/include/net/route.h b/usr/include/net/route.h
new file mode 100644 (file)
index 0000000..a60df24
--- /dev/null
@@ -0,0 +1 @@
+#include <linux/route.h>
diff --git a/usr/include/netinet/if_ether.h b/usr/include/netinet/if_ether.h
new file mode 100644 (file)
index 0000000..060ef22
--- /dev/null
@@ -0,0 +1 @@
+#include <linux/if_ether.h>
diff --git a/usr/include/netinet/in.h b/usr/include/netinet/in.h
new file mode 100644 (file)
index 0000000..2952bb2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netinet/in.h
+ */
+
+#ifndef _NETINET_IN_H
+#define _NETINET_IN_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 (file)
index 0000000..7e6da92
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * netinet/in6.h
+ */
+
+#ifndef _NETINET_IN6_H
+#define _NETINET_IN6_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 (file)
index 0000000..4684bfd
--- /dev/null
@@ -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 (file)
index 0000000..7fc4729
--- /dev/null
@@ -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 (file)
index 0000000..036f588
--- /dev/null
@@ -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 (file)
index 0000000..b5e8e0e
--- /dev/null
@@ -0,0 +1 @@
+#include <linux/if_packet.h>
diff --git a/usr/include/paths.h b/usr/include/paths.h
new file mode 100644 (file)
index 0000000..29ef301
--- /dev/null
@@ -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 (file)
index 0000000..06fb41a
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/poll.h>
diff --git a/usr/include/pwd.h b/usr/include/pwd.h
new file mode 100644 (file)
index 0000000..a319e05
--- /dev/null
@@ -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 (file)
index 0000000..6874855
--- /dev/null
@@ -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 (file)
index 0000000..abebccd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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;
+};
+
+typedef struct __sigjmp_buf sigjmp_buf[1];
+
+#define sigsetjmp(__env, __save) \
+({ \
+  struct __sigjmp_buf *__e = (__env); \
+  sigprocmask(0, NULL, &__e->__sigs); \
+  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 (file)
index 0000000..a513282
--- /dev/null
@@ -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 (file)
index 0000000..cc324b8
--- /dev/null
@@ -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 (file)
index 0000000..6811451
--- /dev/null
@@ -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 (file)
index 0000000..f64f027
--- /dev/null
@@ -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 (file)
index 0000000..21243cc
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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 puts(const char *);
+__extern int fputc(int, FILE *);
+#define putc(c,f)  fputc((c),(f))
+#define putchar(c) fputc((c),stdout)
+
+__extern int fgetc(FILE *);
+__extern char *fgets(char *, int, FILE *);
+#define getc(f) fgetc(f)
+__extern int getc_unlocked(FILE *);
+#define getc_unlocked(f) fgetc(f)
+#define getchar() fgetc(stdin)
+__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 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 size_t fread(void *, size_t, size_t, FILE *);
+__extern size_t fwrite(const void *, size_t, size_t, FILE *);
+
+__extern off_t ftell(FILE *__f);
+#define ftello ftell
+
+__extern int ferror(FILE * );
+__extern int feof(FILE *);
+__extern int fileno(FILE *);
+__extern void clearerr(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;
+}
+
+__extern_inline size_t
+fwrite(const void *__p, size_t __s, size_t __n, FILE * __f)
+{
+       return _fwrite(__p, __s * __n, __f) / __s;
+}
+
+__extern_inline int fileno(FILE *__f)
+{
+       return __f->_IO_fileno;
+}
+
+__extern_inline int ferror(FILE *__f)
+{
+       return __f->_IO_error;
+}
+
+__extern_inline int feof(FILE *__f)
+{
+       return __f->_IO_eof;
+}
+
+__extern_inline void clearerr(FILE *__f)
+{
+       __f->_IO_error = 0;
+       __f->_IO_eof = 0;
+}
+#endif
+
+#endif                         /* _STDIO_H */
diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
new file mode 100644 (file)
index 0000000..406f446
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * stdlib.h
+ */
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+
+#include <malloc.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 *);
+__extern long mrand48(void);
+__extern long nrand48(unsigned short *);
+__extern long lrand48(void);
+__extern unsigned short *seed48(const unsigned short *);
+__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);
+__extern int getpt(void);
+__extern int posix_openpt(int);
+
+static __inline__ int grantpt(int __fd)
+{
+       (void)__fd;
+       return 0;               /* devpts does this all for us! */
+}
+
+#endif                         /* _STDLIB_H */
diff --git a/usr/include/string.h b/usr/include/string.h
new file mode 100644 (file)
index 0000000..0c8c046
--- /dev/null
@@ -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 (file)
index 0000000..fc98ed4
--- /dev/null
@@ -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 (file)
index 0000000..41b5b4a
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _SYS_CAPABILITY_H
+#define _SYS_CAPABILITY_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 (file)
index 0000000..18b7a33
--- /dev/null
@@ -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 (file)
index 0000000..6da2ddb
--- /dev/null
@@ -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 (file)
index 0000000..877b7cd
--- /dev/null
@@ -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 (file)
index 0000000..603b0ce
--- /dev/null
@@ -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 (file)
index 0000000..7b580f3
--- /dev/null
@@ -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 (file)
index 0000000..d64e28b
--- /dev/null
@@ -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 (file)
index 0000000..e08cb05
--- /dev/null
@@ -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 (file)
index 0000000..81ae756
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * sys/ioctl.h
+ */
+
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_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 (file)
index 0000000..02c7217
--- /dev/null
@@ -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 (file)
index 0000000..184e4aa
--- /dev/null
@@ -0,0 +1,32 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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
+
+#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 (file)
index 0000000..56f0b65
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * sys/mman.h
+ */
+
+#ifndef _SYS_MMAN_H
+#define _SYS_MMAN_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>
+#include <asm/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 (file)
index 0000000..9d6b0ee
--- /dev/null
@@ -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 (file)
index 0000000..fb3b2e4
--- /dev/null
@@ -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 (file)
index 0000000..f0c60c2
--- /dev/null
@@ -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 (file)
index 0000000..c12c191
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _SYS_PRCTL_H
+#define _SYS_PRCTL_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 (file)
index 0000000..3337d27
--- /dev/null
@@ -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
+
+/* glibc-ish one-argument version */
+__extern int reboot(int);
+
+/* 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 (file)
index 0000000..5d8bd52
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * sys/resource.h
+ */
+
+#ifndef _SYS_RESOURCE_H
+#define _SYS_RESOURCE_H
+
+#include <klibc/extern.h>
+#include <sys/types.h>         /* MUST be included before linux/resource.h */
+#include <linux/resource.h>
+
+__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 (file)
index 0000000..cc4e00e
--- /dev/null
@@ -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 (file)
index 0000000..a745f10
--- /dev/null
@@ -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 (file)
index 0000000..3334212
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * 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 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/socketcalls.h b/usr/include/sys/socketcalls.h
new file mode 100644 (file)
index 0000000..1c4367d
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * sys/socketcalls.h
+ */
+
+#ifndef _SYS_SOCKETCALLS_H
+#define _SYS_SOCKETCALLS_H
+
+/* socketcalls by number, since <linux/net.h> isn't usable for assembly */
+
+#define SYS_SOCKET      1      /* sys_socket(2)                */
+#define SYS_BIND        2      /* sys_bind(2)                  */
+#define SYS_CONNECT     3      /* sys_connect(2)               */
+#define SYS_LISTEN      4      /* sys_listen(2)                */
+#define SYS_ACCEPT      5      /* sys_accept(2)                */
+#define SYS_GETSOCKNAME 6      /* sys_getsockname(2)           */
+#define SYS_GETPEERNAME 7      /* sys_getpeername(2)           */
+#define SYS_SOCKETPAIR  8      /* sys_socketpair(2)            */
+#define SYS_SEND        9      /* sys_send(2)                  */
+#define SYS_RECV        10     /* sys_recv(2)                  */
+#define SYS_SENDTO      11     /* sys_sendto(2)                */
+#define SYS_RECVFROM    12     /* sys_recvfrom(2)              */
+#define SYS_SHUTDOWN    13     /* sys_shutdown(2)              */
+#define SYS_SETSOCKOPT  14     /* sys_setsockopt(2)            */
+#define SYS_GETSOCKOPT  15     /* sys_getsockopt(2)            */
+#define SYS_SENDMSG     16     /* sys_sendmsg(2)               */
+#define SYS_RECVMSG     17     /* sys_recvmsg(2)               */
+
+#endif                         /* _SYS_SOCKETCALLS_H */
diff --git a/usr/include/sys/splice.h b/usr/include/sys/splice.h
new file mode 100644 (file)
index 0000000..1fa26d9
--- /dev/null
@@ -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 (file)
index 0000000..c4b378e
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <klibc/archstat.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
+
+#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)
+
+#endif
+
+#ifdef _STATBUF_ST_NSEC
+  /* struct stat has struct timespec instead of time_t */
+# define st_atime  st_atim.tv_sec
+# define st_mtime  st_mtim.tv_sec
+# define st_ctime  st_ctim.tv_sec
+#endif
+
+__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 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 (file)
index 0000000..53b3b5e
--- /dev/null
@@ -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 (file)
index 0000000..8fe0142
--- /dev/null
@@ -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/sysinfo.h b/usr/include/sys/sysinfo.h
new file mode 100644 (file)
index 0000000..dba68dc
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * sys/sysinfo.h
+ */
+
+#ifndef _SYS_SYSINFO_H
+#define _SYS_SYSINFO_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 (file)
index 0000000..efb476c
--- /dev/null
@@ -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 (file)
index 0000000..98497e7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * sys/time.h
+ */
+
+#ifndef _SYS_TIME_H
+#define _SYS_TIME_H
+
+#include <klibc/extern.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <linux/time.h>
+
+/* 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 getitimer(int, struct itimerval *);
+__extern int setitimer(int, const struct itimerval *, struct itimerval *);
+__extern int utimes(const char *, const struct timeval *);
+
+#endif                         /* _SYS_TIME_H */
diff --git a/usr/include/sys/times.h b/usr/include/sys/times.h
new file mode 100644 (file)
index 0000000..16be69a
--- /dev/null
@@ -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 (file)
index 0000000..b8cdb8c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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_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_time_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 (file)
index 0000000..ee341fb
--- /dev/null
@@ -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 (file)
index 0000000..e599f67
--- /dev/null
@@ -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 (file)
index 0000000..56288a8
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * sys/utime.h
+ */
+
+#ifndef _SYS_UTIME_H
+#define _SYS_UTIME_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 (file)
index 0000000..fd55c0b
--- /dev/null
@@ -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 (file)
index 0000000..6fb1eab
--- /dev/null
@@ -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 (file)
index 0000000..0f5efaf
--- /dev/null
@@ -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 (file)
index 0000000..ef454b9
--- /dev/null
@@ -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 (file)
index 0000000..71a17e0
--- /dev/null
@@ -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 (file)
index 0000000..59d9859
--- /dev/null
@@ -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 (file)
index 0000000..72b2993
--- /dev/null
@@ -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 (file)
index 0000000..6c08d4e
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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 *);
+__extern int pipe2(int *, 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 open_cloexec(const char *, int, 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;
+static __inline__ int getpagesize(void)
+{
+       return __page_size;
+}
+
+__extern unsigned int __page_shift;
+static __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
+
+#endif                         /* _UNISTD_H */
diff --git a/usr/include/utime.h b/usr/include/utime.h
new file mode 100644 (file)
index 0000000..fa00604
--- /dev/null
@@ -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 (file)
index 0000000..afe324f
--- /dev/null
@@ -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 (file)
index 0000000..0228179
--- /dev/null
@@ -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 (file)
index 0000000..f5a4f24
--- /dev/null
@@ -0,0 +1,3 @@
+lib.a
+kinit
+kinit.shared
diff --git a/usr/kinit/Kbuild b/usr/kinit/Kbuild
new file mode 100644 (file)
index 0000000..5320127
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# 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
+kinit-y  := lib.a
+
+kinit-y  += kinit.o do_mounts.o ramdisk_load.o initrd.o
+kinit-y  += getintfile.o readfile.o xpio.o
+kinit-y  += do_mounts_md.o do_mounts_mtd.o nfsroot.o
+
+kinit-y  += ipconfig/
+kinit-y  += nfsmount/
+kinit-y  += run-init/
+kinit-y  += fstype/
+kinit-y  += resume/
+
+static-y := kinit
+shared-y := kinit.shared
+kinit.shared-y := $(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 += kinit kinit.g kinit.shared kinit.shared.g
+subdir- := fstype ipconfig nfsmount resume run-init
+
+
+# install binary
+install-y := kinit kinit.shared
diff --git a/usr/kinit/README b/usr/kinit/README
new file mode 100644 (file)
index 0000000..fa7f645
--- /dev/null
@@ -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 (file)
index 0000000..2c61025
--- /dev/null
@@ -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 (file)
index 0000000..a32a66a
--- /dev/null
@@ -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 (file)
index 0000000..c327e3b
--- /dev/null
@@ -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 (file)
index 0000000..b648299
--- /dev/null
@@ -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 (file)
index 0000000..99bc6a6
--- /dev/null
@@ -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 (file)
index 0000000..f446620
--- /dev/null
@@ -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 (file)
index 0000000..20d27ca
--- /dev/null
@@ -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 (file)
index 0000000..9b20db1
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# 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
+install-y := $(shared-y)
diff --git a/usr/kinit/fstype/btrfs.h b/usr/kinit/fstype/btrfs.h
new file mode 100644 (file)
index 0000000..459da12
--- /dev/null
@@ -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 (file)
index 0000000..6f5ad4f
--- /dev/null
@@ -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 (file)
index 0000000..775df8f
--- /dev/null
@@ -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 (file)
index 0000000..f958e5c
--- /dev/null
@@ -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 (file)
index 0000000..c5a1432
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * 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;
+}
+
+/*
+ * Check to see if a filesystem is in /proc/filesystems.
+ * Returns 1 if found, 0 if not
+ */
+static int fs_proc_check(const char *fs_name)
+{
+       FILE    *f;
+       char    buf[80], *cp, *t;
+
+       f = fopen("/proc/filesystems", "r");
+       if (!f)
+               return 0;
+       while (fgets(buf, sizeof(buf), f)) {
+               cp = buf;
+               if (!isspace(*cp)) {
+                       while (*cp && !isspace(*cp))
+                               cp++;
+               }
+               while (*cp && isspace(*cp))
+                       cp++;
+               t = strchr(cp, '\n');
+               if (t != NULL)
+                       *t = 0;
+               t = strchr(cp, '\t');
+               if (t != NULL)
+                       *t = 0;
+               t = strchr(cp, ' ');
+               if (t != NULL)
+                       *t = 0;
+               if (!strcmp(fs_name, cp)) {
+                       fclose(f);
+                       return 1;
+               }
+       }
+       fclose(f);
+       return 0;
+}
+
+/*
+ * Check to see if a filesystem is available as a module
+ * Returns 1 if found, 0 if not
+ */
+static int check_for_modules(const char *fs_name)
+{
+       struct utsname  uts;
+       FILE            *f;
+       char            buf[1024], *cp, *t;
+       int             i;
+
+       if (uname(&uts))
+               return 0;
+       snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release);
+
+       f = fopen(buf, "r");
+       if (!f)
+               return 0;
+       while (fgets(buf, sizeof(buf), f)) {
+               cp = strchr(buf, ':');
+               if (cp == NULL)
+                       continue;
+               *cp = 0;
+               cp = strrchr(buf, '/');
+               if (cp == NULL)
+                       continue;
+               cp++;
+               i = strlen(cp);
+               if (i > 3) {
+                       t = cp + i - 3;
+                       if (!strcmp(t, ".ko"))
+                               *t = 0;
+               }
+               if (!strcmp(cp, fs_name)) {
+                       fclose(f);
+                       return 1;
+               }
+       }
+       fclose(f);
+       return 0;
+}
+
+static int base_ext4_image(const void *buf, unsigned long long *bytes,
+                          int *test_fs)
+{
+       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));
+               *test_fs = (sb->s_flags &
+                           __cpu_to_le32(EXT2_FLAGS_TEST_FILESYS)) != 0;
+               return 1;
+       }
+       return 0;
+}
+
+static int ext4_image(const void *buf, unsigned long long *bytes)
+{
+       int ret, test_fs, ext4dev_present, ext4_present;
+
+       ret = base_ext4_image(buf, bytes, &test_fs);
+       if (ret == 0)
+               return 0;
+       ext4dev_present = (fs_proc_check("ext4dev") ||
+                          check_for_modules("ext4dev"));
+       ext4_present = (fs_proc_check("ext4") || check_for_modules("ext4"));
+       if ((test_fs || !ext4_present) && ext4dev_present)
+               return 0;
+       return 1;
+}
+
+static int ext4dev_image(const void *buf, unsigned long long *bytes)
+{
+       int ret, test_fs, ext4dev_present, ext4_present;
+
+       ret = base_ext4_image(buf, bytes, &test_fs);
+       if (ret == 0)
+               return 0;
+       ext4dev_present = (fs_proc_check("ext4dev") ||
+                          check_for_modules("ext4dev"));
+       ext4_present = (fs_proc_check("ext4") || check_for_modules("ext4"));
+       if ((!test_fs || !ext4dev_present) && ext4_present)
+               return 0;
+       return 1;
+}
+
+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, "ext4dev", ext4dev_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 (file)
index 0000000..be2a3e4
--- /dev/null
@@ -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 (file)
index 0000000..028e0c9
--- /dev/null
@@ -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 (file)
index 0000000..efe0733
--- /dev/null
@@ -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 (file)
index 0000000..63132a0
--- /dev/null
@@ -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 (file)
index 0000000..fd8de31
--- /dev/null
@@ -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 (file)
index 0000000..75dfc10
--- /dev/null
@@ -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 (file)
index 0000000..9162bdf
--- /dev/null
@@ -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 (file)
index 0000000..e2899f0
--- /dev/null
@@ -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 (file)
index 0000000..0845edf
--- /dev/null
@@ -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 (file)
index 0000000..b71cb61
--- /dev/null
@@ -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 (file)
index 0000000..af6ccc4
--- /dev/null
@@ -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 (file)
index 0000000..096d505
--- /dev/null
@@ -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 (file)
index 0000000..c490fbc
--- /dev/null
@@ -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 (file)
index 0000000..c18365d
--- /dev/null
@@ -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 (file)
index 0000000..7b7fddb
--- /dev/null
@@ -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 (file)
index 0000000..fd54bc4
--- /dev/null
@@ -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 (file)
index 0000000..fcce247
--- /dev/null
@@ -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 (file)
index 0000000..41ba475
--- /dev/null
@@ -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 (file)
index 0000000..d2efc59
--- /dev/null
@@ -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_cloexec("/", O_RDONLY | O_DIRECTORY, 0);
+       old_fd = open_cloexec("/old", O_RDONLY | O_DIRECTORY, 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, (long)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 (file)
index 0000000..7f8d181
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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
+install-y := $(shared-y)
diff --git a/usr/kinit/ipconfig/README.ipconfig b/usr/kinit/ipconfig/README.ipconfig
new file mode 100644 (file)
index 0000000..5c8227a
--- /dev/null
@@ -0,0 +1,106 @@
+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 up to seven elements, separated by colons:
+
+<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
+
+  <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.
+
+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 (file)
index 0000000..1d5bd0d
--- /dev/null
@@ -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 (file)
index 0000000..150ebfa
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * 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;
+}
+
+/*
+ * 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;
+
+       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;
+                       }
+
+                       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;
+               }
+       }
+
+       /*
+        * 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 (file)
index 0000000..60873ce
--- /dev/null
@@ -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 (file)
index 0000000..ebf79cc
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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 */
+};
+
+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;
+       bootp.yiaddr    = dev->ip_addr;
+       bootp.giaddr    = INADDR_ANY;
+       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 (file)
index 0000000..0fba92f
--- /dev/null
@@ -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 (file)
index 0000000..d1d7e42
--- /dev/null
@@ -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 (file)
index 0000000..7be2a1f
--- /dev/null
@@ -0,0 +1,870 @@
+#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;
+
+/* 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)
+{
+       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));
+       printf(" gateway: %-16s ", my_inet_ntoa(dev->ip_gateway));
+       printf("dns0     : %-16s ", my_inet_ntoa(dev->ip_nameserver[0]));
+       printf("dns1   : %-16s\n", 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_setdefaultroute(dev))
+               printf("IP-Config: failed to set default route 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));
+               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);
+
+       ++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;
+
+       /*
+        * Is the link up?  If not, try again in 1 second.
+        */
+       if (!netdev_running(s->dev)) {
+               s->expire = now + 1;
+               s->state = s->restart_state;
+               return;
+       }
+
+       /*
+        * 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 + 10;
+       } else {
+               s->expire = now + s->retry_period;
+
+               s->retry_period *= 2;
+               if (s->retry_period > 60)
+                       s->retry_period = 60;
+       }
+}
+
+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 pkt_fd, time_t now)
+{
+       int ret = 0;
+       struct state *s;
+
+       for (s = slist; s; s = s->next)
+               ret |= process_receive_event(s, now);
+       return ret;
+}
+
+static int loop(void)
+{
+#define NR_FDS 1
+       struct pollfd fds[NR_FDS];
+       struct state *s;
+       int pkt_fd;
+       int nr = 0, rc = 0;
+       struct timeval now, prev;
+       time_t start;
+
+       pkt_fd = packet_open();
+       if (pkt_fd == -1) {
+               perror("packet_open");
+               return -1;
+       }
+
+       fds[0].fd = pkt_fd;
+       fds[0].events = POLLRDNORM;
+
+       gettimeofday(&now, NULL);
+       start = now.tv_sec;
+       while (1) {
+               int timeout = 60;
+               int pending = 0;
+               int done = 0;
+               int timeout_ms;
+               int x;
+
+               for (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 (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, NR_FDS, timeout_ms);
+                       prev = now;
+                       gettimeofday(&now, NULL);
+
+                       if ((nr > 0) && (fds[0].revents & POLLRDNORM)) {
+                               if (do_pkt_recv(pkt_fd, now.tv_sec) == 1)
+                                       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:
+       packet_close();
+
+       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;
+
+       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, const 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 (opt > 6) {
+                               fprintf(stderr,
+                                       "%s: too many options for %s\n",
+                                       progname, dev->name);
+                               longjmp(abort_buf, 1);
+                       }
+
+                       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;
+                       }
+               }
+       }
+
+       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(const 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;
+
+       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 (file)
index 0000000..e203d0c
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * 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_setdefaultroute(struct netdev *dev)
+{
+       struct rtentry r;
+
+       if (dev->ip_gateway == INADDR_ANY)
+               return 0;
+
+       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 (file)
index 0000000..cd853b6
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef IPCONFIG_NETDEV_H
+#define IPCONFIG_NETDEV_H
+
+#include <sys/utsname.h>
+#include <net/if.h>
+
+#define BPLEN          256
+#define FNLEN          128                     /* from DHCP  RFC 2131 */
+
+struct netdev {
+       const 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  */
+       long uptime;            /* when complete configuration */
+       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_setdefaultroute(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);
+}
+
+#endif /* IPCONFIG_NETDEV_H */
diff --git a/usr/kinit/ipconfig/packet.c b/usr/kinit/ipconfig/packet.c
new file mode 100644 (file)
index 0000000..446073a
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * 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"
+
+static int pkt_fd = -1;
+
+uint16_t cfg_local_port = LOCAL_PORT;
+uint16_t cfg_remote_port = REMOTE_PORT;
+
+int packet_open(void)
+{
+       int fd, one = 1;
+
+       if (pkt_fd != -1)
+               return pkt_fd;
+
+       /*
+        * 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);
+               fd = -1;
+       }
+
+       pkt_fd = fd;
+
+       return fd;
+}
+
+void packet_close(void)
+{
+       close(pkt_fd);
+       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));
+
+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(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(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(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(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 (file)
index 0000000..f6cef52
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef IPCONFIG_PACKET_H
+#define IPCONFIG_PACKET_H
+
+struct iovec;
+
+int packet_open(void);
+void packet_close(void);
+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 (file)
index 0000000..523c92b
--- /dev/null
@@ -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="),
+                         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 (file)
index 0000000..ee006f4
--- /dev/null
@@ -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 (file)
index 0000000..d8c1736
--- /dev/null
@@ -0,0 +1,204 @@
+#include <ctype.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;
+}
+
+/*
+ *     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
+ *
+ *     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 (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 (file)
index 0000000..461e6f3
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# 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
+install-y := $(shared-y)
diff --git a/usr/kinit/nfsmount/README.locking b/usr/kinit/nfsmount/README.locking
new file mode 100644 (file)
index 0000000..bf2e8e7
--- /dev/null
@@ -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 (file)
index 0000000..a4e8014
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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)
+{
+       struct sockaddr_in sin;
+       int pktlen, addrlen;
+       union {
+               struct rpc_call rpc;
+               /* Max UDP packet size + unused TCP fragment size */
+               char payload[MAX_UDP_PACKET + offsetof(struct rpc_header, udp)];
+       } 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 (file)
index 0000000..37650bf
--- /dev/null
@@ -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 (file)
index 0000000..d81a141
--- /dev/null
@@ -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 (file)
index 0000000..36b29a5
--- /dev/null
@@ -0,0 +1,269 @@
+#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          = 7,
+       .retrans        = 3,
+       .acregmin       = 3,
+       .acregmax       = 60,
+       .acdirmin       = 30,
+       .acdirmax       = 60,
+       .namlen         = NAME_MAX,
+};
+
+int nfs_port;
+
+static struct int_opts {
+       char *name;
+       int *val;
+} int_opts[] = {
+       {"port",        &nfs_port},
+       {"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);
+                       }
+               }
+       }
+}
+
+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 (file)
index 0000000..e0687a6
--- /dev/null
@@ -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));
+
+struct mount_reply {
+       struct rpc_reply reply;
+       uint32_t status;
+       struct nfs_fh_wire fh;
+} __attribute__ ((packed));
+
+#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 (file)
index 0000000..7b28ded
--- /dev/null
@@ -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 (file)
index 0000000..0a3e2d0
--- /dev/null
@@ -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 (file)
index 0000000..0a7fcf5
--- /dev/null
@@ -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 (file)
index 0000000..1bcfeea
--- /dev/null
@@ -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 (file)
index 0000000..3b80773
--- /dev/null
@@ -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 (file)
index 0000000..2b3503a
--- /dev/null
@@ -0,0 +1,272 @@
+#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, 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);
+}
+
+/* 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;
+}
+
+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 (file)
index 0000000..7a16b4a
--- /dev/null
@@ -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 (file)
index 0000000..034195d
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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
+install-y := $(shared-y)
diff --git a/usr/kinit/resume/resume.c b/usr/kinit/resume/resume.c
new file mode 100644 (file)
index 0000000..2138078
--- /dev/null
@@ -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 (file)
index 0000000..5fb929f
--- /dev/null
@@ -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 (file)
index 0000000..e557b05
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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 powerfd = -1;
+       char device_string[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 ((powerfd = open("/sys/power/resume", O_WRONLY)) < 0)
+               goto fail_r;
+
+       len = snprintf(device_string, sizeof device_string,
+                      "%u:%u:%llu",
+                      major(resume_device), minor(resume_device),
+                      resume_offset);
+
+       /* This should never happen */
+       if (len >= sizeof device_string)
+               goto fail_r;
+
+       dprintf("kinit: trying to resume from %s\n", resume_file);
+
+       if (write(powerfd, device_string, len) != len)
+               goto fail_r;
+
+       /* Okay, what are we still doing alive... */
+failure:
+       if (powerfd >= 0)
+               close(powerfd);
+       dprintf("kinit: No resume image, doing normal boot...\n");
+       return -1;
+
+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 (file)
index 0000000..f7832b7
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# 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
+install-y := $(shared-y)
diff --git a/usr/kinit/run-init/run-init.c b/usr/kinit/run-init/run-init.c
new file mode 100644 (file)
index 0000000..2147d06
--- /dev/null
@@ -0,0 +1,97 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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] /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:
+ *
+ * - Delete all files in the initramfs;
+ * - Remounts /real-root onto the root filesystem;
+ * - Drops comma-separated list of capabilities;
+ * - Chroots;
+ * - Opens /dev/console;
+ * - Spawns the specified init program (with arguments.)
+ */
+
+#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] /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;
+       char **initargs;
+
+       /* Variables... */
+       int o;
+
+       /* Parse the command line */
+       program = argv[0];
+
+       while ((o = getopt(argc, argv, "c:d:")) != -1) {
+               if (o == 'c') {
+                       console = optarg;
+               } else if (o == 'd') {
+                       drop_caps = optarg;
+               } 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, init, initargs);
+
+       /* If run_init returns, something went wrong */
+       fprintf(stderr, "%s: %s: %s\n", program, error, strerror(errno));
+       return 1;
+}
diff --git a/usr/kinit/run-init/run-init.h b/usr/kinit/run-init/run-init.h
new file mode 100644 (file)
index 0000000..da3136a
--- /dev/null
@@ -0,0 +1,34 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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
+
+const char *run_init(const char *realroot, const char *console,
+                    const char *drop_caps, 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 (file)
index 0000000..fe856bd
--- /dev/null
@@ -0,0 +1,216 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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, 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, const char *init,
+                    char **initargs)
+{
+       struct stat rst, cst;
+       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... */
+
+       /* 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";
+       dup2(confd, 0);
+       dup2(confd, 1);
+       dup2(confd, 2);
+       close(confd);
+
+       /* Spawn init */
+       execv(init, initargs);
+       return init;            /* Failed to spawn init */
+}
diff --git a/usr/kinit/xpio.c b/usr/kinit/xpio.c
new file mode 100644 (file)
index 0000000..42a9844
--- /dev/null
@@ -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 (file)
index 0000000..0596a32
--- /dev/null
@@ -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 (file)
index 0000000..f24c971
--- /dev/null
@@ -0,0 +1,12 @@
+errlist.c
+.interp.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 (file)
index 0000000..5e991cb
--- /dev/null
@@ -0,0 +1,50 @@
+         -------------------------------------------------
+         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 -- regardless of the value of
+the extra argument.
+
+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 (file)
index 0000000..40d43c7
--- /dev/null
@@ -0,0 +1,188 @@
+#
+# 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 open_cloexec.o \
+         fread2.o fwrite2.o fgets.o fputc.o fputs.o puts.o putchar.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 \
+         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 getpt.o posix_openpt.o isatty.o reboot.o \
+         time.o utime.o lseek.o nice.o getpriority.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 \
+         send.o recv.o \
+         access.o chmod.o chown.o dup2.o mknod.o poll.o rename.o stat.o \
+         lchown.o link.o rmdir.o unlink.o utimes.o lstat.o mkdir.o \
+         readlink.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
+
+klib-$(CONFIG_KLIBC_ERRLIST) += errlist.o
+
+ifeq ($(CONFIG_KLIBC_ERRLIST),y)
+KLIBCCFLAGS_strerror.o += -DWITH_ERRLIST
+endif
+
+#####
+# Shared definitions
+LIBC     := libc.a
+SOLIB    := libc.so
+SOHASH   := klibc.so
+CRT0     := arch/$(KLIBCARCHDIR)/crt0.o
+INTERP_O := interp.o
+
+always   := $(LIBC) $(SOLIB) $(SOHASH) $(INTERP_O)
+LIBC     := $(call objectify,$(LIBC))
+SOLIB    := $(call objectify,$(SOLIB))
+SOHASH   := $(call objectify,$(SOHASH))
+CRT0     := $(call objectify,$(CRT0))
+INTERP_O := $(call objectify,$(INTERP_O))
+
+SOLIBHASH = $(shell cat $(SOLIB).hash)
+
+#####
+# Readable errormessages extracted from src..
+targets += errlist.c
+quiet_cmd_errlist = GEN     $@
+      cmd_errlist = $(PERL) $< $(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 $@;                                             \
+                 $(call klibc-ar,cq,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 interp.o
+targets += interp.o
+
+quiet_cmd_interp = BUILD   $@
+      cmd_interp = $(KLIBCCC) $(klibccflags) -D__ASSEMBLY__     \
+                             -DLIBDIR=\"$(SHLIBDIR)\"         \
+                            -DSOHASH=\"$(SOLIBHASH)\" \
+                            -c -o $@ $<
+
+$(INTERP_O): $(obj)/interp.S $(SOLIB).hash
+       $(call if_changed,interp)
+
+#####
+# Install klibc
+install-rule:
+       @echo "  INSTALL klibc to $(INSTALLROOT)$(INSTALLDIR)/$(KLIBCCROSS)lib"
+       $(Q)$(foreach f, $(LIBC) $(SOLIB) $(CRT0) $(INTERP_O), \
+         $(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)
diff --git a/usr/klibc/LICENSE b/usr/klibc/LICENSE
new file mode 100644 (file)
index 0000000..aa6d7a7
--- /dev/null
@@ -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 (file)
index 0000000..c72ae47
--- /dev/null
@@ -0,0 +1,77 @@
+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.
+
+
+The build procedure is not very polished yet, but it should work like
+this:
+
+a) Extract a recent Linux kernel into a directory and run
+   "make headers_install".
+   Now enter the klibc dir and point KLIBCKERNELSRC to the
+   path of the configured linux tree
+   "make  KLIBCKERNELSRC=`pwd`/../linux/usr/".
+
+
+b) If you're cross-compiling, you need to set KLIBCARCH to the
+   appropriate architecture, and set CROSS_COMPILE to your toolchain
+   prefix.
+
+   IMPORTANT: if you're on a 64-bit machine with a 32-bit userland
+   (ia64, mips64, ppc64 sparc64, s390x or x86_64), and you want to
+   build the 32-bit version: you need to set KLIBCARCH to the 32-bit
+   architecture as well as set up the linux/include/asm symlink to
+   point to the 32-bit architecture.  Building the 32-bit architecture
+   usually (but not always) produces smaller binaries, and is likely
+   to be better tested.
+
+   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.
+
+   The following is the last known status of various architectures:
+
+   alpha:       Working
+   arm-thumb:   Untested
+   arm:                 Working
+   arm26:       Not yet ported
+   arm64:       Working
+   avr32:       Not yet ported
+   cris:        Working
+   h8300:       Not yet ported
+   i386:        Working
+   ia64:        Working static, shared untested
+   m32r:        Untested
+   m68k:        Working
+   mips:        Working
+   mips64:      Not yet ported
+   parisc:      Untested
+   parisc64:    Not yet ported
+   ppc:                 Working
+   ppc64:       Working
+   s390:        Working
+   s390x:       Working
+   sh:          Runtime breakage
+   sh64:        Not yet ported
+   sparc:       Working
+   sparc64:     Working
+   v850:        Not yet ported
+   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.
+
+c) Try the test programs in the tests/ directory.  They should run...
+
+Contact the klibc mailing list:
+
+       http://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 (file)
index 0000000..39f7db5
--- /dev/null
@@ -0,0 +1,21 @@
+/* -*- 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 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 (file)
index 0000000..41cfa17
--- /dev/null
@@ -0,0 +1,289 @@
+/* -*- 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> 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,m32r,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 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);
+<?!ppc64> int stat64,stat::stat(const char *, struct stat *);
+<?!ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
+<!ppc64> int fstat64,fstat::fstat(int, struct stat *);
+<ppc64> int stat::stat(const char *, struct stat *);
+<ppc64> int lstat::lstat(const char *, struct stat *);
+<ppc64> int fstat::fstat(int, struct stat *);
+/* XXX: Is this right?! */
+<?> int fstatat64,newfstatat,fstatat::fstatat(int, const char *, struct stat *, int);
+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);
+<?> int utime(const char *, const struct utimbuf *);
+<?> int utimes(const char *, const struct timeval *);
+<?> int futimesat(int, const char *, const struct timeval *);
+<?> 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);
+<?> int _newselect,select::select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *);
+#elif defined(__NR_pselect7)
+int pselect7::__pselect7(int, fd_set *, fd_set *, fd_set *, struct timespec *, const sigset_t *, size_t);
+#elif defined(__NR_pselect6)
+int pselect6::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *);
+#endif
+<?> int poll(struct pollfd *, nfds_t, long);
+<?> 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);
+ssize_t pread64,pread::pread(int, void *, size_t, off_t);
+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
+ *
+ * We really should get rid of the non-rt_* of these, but that takes
+ * sanitizing <signal.h> for all architectures, sigh.  See <klibc/config.h>.
+ */
+#if _KLIBC_USE_RT_SIG
+<!sparc,sparc64,alpha> 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 *);
+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);
+<sparc64> void rt_sigreturn::__sigreturn();
+#else
+int sigaction::__sigaction(int, const struct sigaction *, struct sigaction *);
+int sigpending(sigset_t *);
+int sigprocmask(int, const sigset_t *, sigset_t *);
+/*
+ * There is no single calling convention for the old sigsuspend.
+ * If your architecture is not listed here, building klibc shall
+ * rather fail than use a broken calling convention.
+ * You better switch to RT signals on those architectures:
+ * blackfin h8300 microblaze mips.
+ *
+ * The arguments other than the sigset_t are assumed ignored.
+ */
+<cris,sh,sparc,alpha,ppc,sparc64> int sigsuspend::__sigsuspend_s(sigset_t);
+<arm,frv,i386,m68k,mn10300,s390,s390x> int sigsuspend::__sigsuspend_xxs(int, int, sigset_t);
+#endif
+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
+ */
+<?> time_t time(time_t *);
+clock_t times(struct tms *);
+int gettimeofday(struct timeval *, struct timezone *);
+int settimeofday(const struct timeval *, const struct timezone *);
+int nanosleep(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 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 (file)
index 0000000..30d415c
--- /dev/null
@@ -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 (file)
index 0000000..592a3db
--- /dev/null
@@ -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 (file)
index 0000000..d174b8e
--- /dev/null
@@ -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 (file)
index 0000000..0b59eed
--- /dev/null
@@ -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 (file)
index 0000000..4629a17
--- /dev/null
@@ -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/access.c b/usr/klibc/access.c
new file mode 100644 (file)
index 0000000..0f24856
--- /dev/null
@@ -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 (file)
index 0000000..8bd74c5
--- /dev/null
@@ -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 (file)
index 0000000..d420495
--- /dev/null
@@ -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 (file)
index 0000000..662b9d3
--- /dev/null
@@ -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 (file)
index 0000000..f5c30f3
--- /dev/null
@@ -0,0 +1,52 @@
+# -*- 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 setjmp.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) \
+                        -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 (file)
index 0000000..e7dc61a
--- /dev/null
@@ -0,0 +1,16 @@
+# -*- 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       = -Ttext 0x1c0000200
diff --git a/usr/klibc/arch/alpha/README-gcc b/usr/klibc/arch/alpha/README-gcc
new file mode 100644 (file)
index 0000000..1d0052f
--- /dev/null
@@ -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 (file)
index 0000000..5e2babb
--- /dev/null
@@ -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 (file)
index 0000000..c44254f
--- /dev/null
@@ -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 (file)
index 0000000..ee72413
--- /dev/null
@@ -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 (file)
index 0000000..ed604bd
--- /dev/null
@@ -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/syscall.S b/usr/klibc/arch/alpha/syscall.S
new file mode 100644 (file)
index 0000000..ae69ef2
--- /dev/null
@@ -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 (file)
index 0000000..1719e37
--- /dev/null
@@ -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
+       mov     v0, a4
+       beq     a3, 1f
+       br      pv, 2f                  # pv <- pc
+2:
+       ldgp    gp, 0(pv)
+       lda     a1, errno
+       lda     v0, -1(zero)
+       stl     a3, 0(a1)
+1:
+       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 (file)
index 0000000..08b97e8
--- /dev/null
@@ -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 (file)
index 0000000..4946b6b
--- /dev/null
@@ -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 (file)
index 0000000..53bc1dc
--- /dev/null
@@ -0,0 +1,35 @@
+# -*- 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
+KLIBCLDFLAGS  += --thumb-entry _start
+KLIBCEMAIN     = --thumb-entry main
+KLIBCREQFLAGS += -mabi=aapcs-linux
+KLIBCSHAREDFLAGS = -Ttext 0x380200
+else
+# 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
+KLIBCSHAREDFLAGS = -Ttext 0x01800200
+ifeq ($(CONFIG_AEABI),y)
+KLIBCREQFLAGS += -mabi=aapcs-linux -mno-thumb-interwork
+else
+KLIBCREQFLAGS += -mabi=apcs-gnu -mno-thumb-interwork
+endif
+endif
diff --git a/usr/klibc/arch/arm/__muldi3.c b/usr/klibc/arch/arm/__muldi3.c
new file mode 100644 (file)
index 0000000..3fdeb2b
--- /dev/null
@@ -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 (file)
index 0000000..c69eb11
--- /dev/null
@@ -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 (file)
index 0000000..1e81f8e
--- /dev/null
@@ -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 (file)
index 0000000..9f96274
--- /dev/null
@@ -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 (file)
index 0000000..e5b04e2
--- /dev/null
@@ -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 (file)
index 0000000..1a4eca0
--- /dev/null
@@ -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 (file)
index 0000000..7130b65
--- /dev/null
@@ -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 (file)
index 0000000..f8643b5
--- /dev/null
@@ -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 (file)
index 0000000..82664a7
--- /dev/null
@@ -0,0 +1,23 @@
+# -*- 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
+
+# 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 = -Ttext 0x0200000
diff --git a/usr/klibc/arch/arm64/crt0.S b/usr/klibc/arch/arm64/crt0.S
new file mode 100644 (file)
index 0000000..0b2dd32
--- /dev/null
@@ -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 (file)
index 0000000..284e328
--- /dev/null
@@ -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 (file)
index 0000000..3ce91fb
--- /dev/null
@@ -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     x0, [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 (file)
index 0000000..095b1e8
--- /dev/null
@@ -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 (file)
index 0000000..c30b2a0
--- /dev/null
@@ -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/cris/Kbuild b/usr/klibc/arch/cris/Kbuild
new file mode 100644 (file)
index 0000000..13ceeec
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# klibc files fora cris
+#
+
+always  := crt0.o
+targets := crt0.o
+
+klib-y += __negdi2.o setjmp.o syscall.o vfork.o
+
+klib-y += ../../libgcc/__divdi3.o     ../../libgcc/__moddi3.o
+klib-y += ../../libgcc/__udivdi3.o    ../../libgcc/__umoddi3.o
+klib-y += ../../libgcc/__udivmoddi4.o
+
+# Divide support
+klib-y := __Umod.o __Udiv.o __Mod.o __Div.o
+
+quiet_cmd_cc-div = DIV-CC  $@
+      cmd_cc-div = $(KLIBCC) $(klibccflags) -c -o $@ $<
+
+
+$(obj)/__Umod.o: $(src)/divide.c
+KLIBCCFLAGS___Umod.o := -DSIGNED=0 -DREM=1 -DBITS=32 -DNAME=__Umod
+$(obj)/__Udiv.o: $(src)/divide.c
+KLIBCCFLAGS___Udiv.o := -DSIGNED=0 -DREM=0 -DBITS=32 -DNAME=__Udiv
+$(obj)/__Mod.o: $(src)/divide.c
+KLIBCCFLAGS___Mod.o  := -DSIGNED=1 -DREM=1 -DBITS=32 -DNAME=__Mod
+$(obj)/__Div.o: $(src)/divide.c
+KLIBCCFLAGS___Div.o  := -DSIGNED=1 -DREM=0 -DBITS=32 -DNAME=__Div
diff --git a/usr/klibc/arch/cris/MCONFIG b/usr/klibc/arch/cris/MCONFIG
new file mode 100644 (file)
index 0000000..20bfe73
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- makefile -*-
+#
+# arch/cris/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
+# 224 MB - normal binaries start at 0
+# (lib?)gcc on cris seems to insist on producing .init and .fini sections
+KLIBCSHAREDFLAGS     = --section-start .init=0x0e000100
+
+# The CRIS compiler needs an -iprefix to find libgcc includes when
+# nostdinc is used. It also needs -mlinux to compile linux applications.
+INCLUDE_PREFIX  = $(shell $(CC) -print-libgcc-file-name | sed -e s/libgcc.a//)
+KLIBCARCHREQFLAGS = -iprefix $(INCLUDE_PREFIX) -mlinux
+
+# Special flags needed for linking
+KLIBCLDFLAGS   += -mcrislinux
diff --git a/usr/klibc/arch/cris/__negdi2.S b/usr/klibc/arch/cris/__negdi2.S
new file mode 100644 (file)
index 0000000..3cca9ed
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * arch/cris/__negdi2.c
+ */
+
+/*
+ * In 2's complement arithmetric, -x == (~x + 1), so
+ * -{h,l} = (~{h,l} + {0,1)
+ * -{h,l} = {~h,~l} + {0,1}
+ * -{h,l} = {~h + cy, ~l + 1}
+ * ... where cy = (l == 0)
+ * -{h,l} = {~h + cy, -l}
+ */
+
+       .text
+       .balign 4
+       .type   __negdi2,@function
+       .globl  __negdi2
+__negdi2:
+       neg.d   $r10,$r10
+       seq     $r12
+       not     $r11
+       ret
+         add.d $r12,$r11
+
+       .size __negdi2, .-__negdi2
diff --git a/usr/klibc/arch/cris/crt0.S b/usr/klibc/arch/cris/crt0.S
new file mode 100644 (file)
index 0000000..22cb9b4
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# arch/cris/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
+       .balign 4
+       .type   _start,@function
+       .globl  _start
+_start:
+       /* Save the address of the ELF argument array */
+       move.d  $sp,$r10        /* Address of ELF arguments */
+
+       /* atexit() function (assume null) */
+       moveq   0,$r11
+
+       /* Set up a dummy stack frame to keep gcc from getting confused */
+       push    $r11
+       push    $r11
+       jump    __libc_init
+
+       .size _start, .-_start
diff --git a/usr/klibc/arch/cris/divide.c b/usr/klibc/arch/cris/divide.c
new file mode 100644 (file)
index 0000000..1d4ab23
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdint.h>
+#include <signal.h>
+
+#if BITS == 64
+typedef uint64_t unum;
+typedef int64_t snum;
+#else
+typedef uint32_t unum;
+typedef int32_t snum;
+#endif
+
+#ifdef SIGNED
+typedef snum xnum;
+#else
+typedef unum xnum;
+#endif
+
+#ifdef __cris__
+static inline unum __attribute__ ((const))dstep(unum rs, unum rd)
+{
+       asm("dstep %1,%0": "+r"(rd):"r"(rs));
+       return rd;
+}
+
+static inline unum __attribute__ ((const))lz(unum rs)
+{
+       unum rd;
+       asm("lz %1,%0": "=r"(rd):"r"(rs));
+       return rd;
+}
+
+#else
+/* For testing */
+static inline unum __attribute__ ((const))dstep(unum rs, unum rd)
+{
+       rd <<= 1;
+       if (rd >= rs)
+               rd -= rs;
+
+       return rd;
+}
+
+static inline unum __attribute__ ((const))lz(unum rs)
+{
+       unum rd = 0;
+       while (rs >= 0x7fffffff) {
+               rd++;
+               rs <<= 1;
+       }
+       return rd;
+}
+
+#endif
+
+xnum NAME(unum num, unum den)
+{
+       unum quot = 0, qbit = 1;
+       int minus = 0;
+       xnum v;
+
+       if (den == 0) {
+               raise(SIGFPE);
+               return 0;       /* If signal ignored... */
+       }
+
+       if (den == 1)
+               return (xnum) (REM ? 0 : num);
+
+#if SIGNED
+       if ((snum) (num ^ den) < 0)
+               minus = 1;
+       if ((snum) num < 0)
+               num = -num;
+       if ((snum) den < 0)
+               den = -den;
+#endif
+
+       den--;
+
+       /* Left-justify denominator and count shift */
+       while ((snum) den >= 0) {
+               den <<= 1;
+               qbit <<= 1;
+       }
+
+       while (qbit) {
+               if (den <= num) {
+                       num -= den;
+                       quot += qbit;
+               }
+               den >>= 1;
+               qbit >>= 1;
+       }
+
+       v = (xnum) (REM ? num : quot);
+       if (minus)
+               v = -v;
+       return v;
+}
diff --git a/usr/klibc/arch/cris/setjmp.S b/usr/klibc/arch/cris/setjmp.S
new file mode 100644 (file)
index 0000000..2041b82
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# arch/cris/setjmp.S
+#
+# setjmp/longjmp for the cris architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#      $r8..$r0        (in that order)
+#      $sp     ($r14)
+#      return address
+#
+
+       .text
+       .balign 4
+       .globl  setjmp
+       .type   setjmp, @function
+setjmp:
+       movem   $r8,[$r10+]             /* Save $r8..$r0 at $r10... */
+       move.d  $sp,[$r10+]
+       move    $srp,[$r10]
+       ret
+         moveq 0,$r10
+
+       .size setjmp,.-setjmp
+
+       .text
+       .balign 4
+       .globl  longjmp
+       .type   longjmp, @function
+longjmp:
+       movem   [$r10+],$r8             /* Load $r8..$r0 from $r10... */
+       move.d  [$r10+],$sp
+       jump    [$r10]
+       move.d $r11,$r10
+
+       .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/cris/syscall.S b/usr/klibc/arch/cris/syscall.S
new file mode 100644 (file)
index 0000000..d71495a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * arch/cris/syscall.S
+ *
+ * On cris, r9 contains the syscall number (set by generated stub);
+ * r10..r13 contain arguments 0-3 per the standard calling convention,
+ * and arguments 4-5 are passed in $mof and $srp; however, we have
+ * to save $srp around the system call.
+ */
+
+       .section ".text","ax"
+       .balign 4
+       .globl  __syscall_common
+       .type   __syscall_common,@function
+__syscall_common:
+       push    $srp
+       move    [$sp+4],$mof
+       move    [$sp+8],$srp
+       break   13
+
+       cmps.w  -4096,$r10
+       blo     1f
+       neg.d   $r10,$r11
+       move.d  $r11,[errno]
+       moveq   -1,$r10
+1:
+       pop     $srp
+       ret
+       nop
+
+       .size   __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/cris/sysstub.ph b/usr/klibc/arch/cris/sysstub.ph
new file mode 100644 (file)
index 0000000..182ad73
--- /dev/null
@@ -0,0 +1,29 @@
+# -*- perl -*-
+#
+# arch/cris/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.type\t${fname},\@function\n";
+    print OUT "\t.globl\t${fname}\n";
+    print OUT "\t.balign\t4\n";
+    print OUT "${fname}:\n";
+    print OUT "#if __NR_${sname} <= 31\n";
+    print OUT "\t  moveq\t__NR_${sname}, \$r9\n";
+    print OUT "#else\n";
+    print OUT "\t  move.d\t__NR_${sname}, \$r9\n";
+    print OUT "#endif\n";
+    print OUT "\tjump\t__syscall_common\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/cris/vfork.S b/usr/klibc/arch/cris/vfork.S
new file mode 100644 (file)
index 0000000..ccdb36c
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/cris/vfork.S
+ *
+ * On cris, r9 contains the syscall number (set by generated stub);
+ * r10..r13 contain arguments 0-3 per the standard calling convention.
+ * The return address is in $srp; so we just need to avoid the stack
+ * usage of the normal syscall stubs.
+ */
+
+#include <asm/unistd.h>
+
+       .section ".text","ax"
+       .balign 4
+       .globl  vfork
+       .type   vfork,@function
+vfork:
+       move.d  __NR_vfork, $r9
+       break   13
+
+       cmps.w  -4096,$r10
+       blo     1f
+       neg.d   $r10,$r11
+       move.d  $r11,[errno]
+       moveq   -1,$r10
+1:
+       ret
+       nop
+
+       .size   vfork,.-vfork
diff --git a/usr/klibc/arch/i386/Kbuild b/usr/klibc/arch/i386/Kbuild
new file mode 100644 (file)
index 0000000..1642374
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# klibc .o files for i386
+#
+
+klib-y := archinit.o socketcall.o 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 (file)
index 0000000..1150ece
--- /dev/null
@@ -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       = -Ttext 0x06000200
+
+# Asm includes for i386 are in the merged x86 tree
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)/arch/x86/include
diff --git a/usr/klibc/arch/i386/archinit.c b/usr/klibc/arch/i386/archinit.c
new file mode 100644 (file)
index 0000000..111d130
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/i386/archinit.c
+ *
+ * Architecture-specific libc initialization
+ */
+
+#include <stdint.h>
+#include <klibc/compiler.h>
+#include <elf.h>
+#include <sys/auxv.h>
+
+extern void (*__syscall_entry)(int, ...);
+
+void __libc_archinit(void)
+{
+       if (__auxval[AT_SYSINFO])
+               __syscall_entry = (void (*)(int, ...)) __auxval[AT_SYSINFO];
+}
diff --git a/usr/klibc/arch/i386/crt0.S b/usr/klibc/arch/i386/crt0.S
new file mode 100644 (file)
index 0000000..8c6635e
--- /dev/null
@@ -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 (file)
index 0000000..7344142
--- /dev/null
@@ -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 (file)
index 0000000..7666eb2
--- /dev/null
@@ -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 (file)
index 0000000..6a63c52
--- /dev/null
@@ -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 (file)
index 0000000..472c7cc
--- /dev/null
@@ -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 (file)
index 0000000..147ad94
--- /dev/null
@@ -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 (file)
index 0000000..7cd136c
--- /dev/null
@@ -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 (file)
index 0000000..2dfdfe2
--- /dev/null
@@ -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 (file)
index 0000000..b766792
--- /dev/null
@@ -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/socketcall.S b/usr/klibc/arch/i386/socketcall.S
new file mode 100644 (file)
index 0000000..44e2004
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# socketcall.S
+#
+# Socketcalls use the following convention:
+# %eax = __NR_socketcall
+# %ebx = socketcall number
+# %ecx = pointer to arguments (up to 6)
+#
+
+#include <asm/unistd.h>
+
+#ifdef __i386__
+
+       .text
+       .align 4
+       .globl __socketcall_common
+       .type __socketcall_common, @function
+
+__socketcall_common:
+       xchgl   %ebx,(%esp)     # The stub passes the socketcall # on stack
+
+#ifdef _REGPARM
+       pushl   16(%esp)        # Arg 6
+       pushl   16(%esp)        # Arg 5
+       pushl   16(%esp)        # Arg 4
+       pushl   %ecx
+       pushl   %edx
+       pushl   %eax
+       movl    %esp,%ecx
+#else
+       leal    8(%esp),%ecx    # Arguments already contiguous on-stack
+#endif
+
+       movl    $__NR_socketcall,%eax
+       call    *__syscall_entry
+
+#ifdef _REGPARM
+       addl    $6*4, %esp
+#endif
+
+       cmpl    $-4095,%eax     # Error return?
+
+       popl    %ebx
+
+       jb      1f
+
+       negl    %eax
+       movl    %eax,errno
+       orl     $-1,%eax        # Return -1
+1:
+       ret
+
+       .size __socketcall_common,.-__socketcall_common
+
+#endif
diff --git a/usr/klibc/arch/i386/syscall.S b/usr/klibc/arch/i386/syscall.S
new file mode 100644 (file)
index 0000000..b7814e8
--- /dev/null
@@ -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 (file)
index 0000000..e73a3ff
--- /dev/null
@@ -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 (file)
index 0000000..e796a93
--- /dev/null
@@ -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 (file)
index 0000000..d32b9b9
--- /dev/null
@@ -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 (file)
index 0000000..49070ff
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# klibc files for ia64
+#
+
+klib-y := vfork.o setjmp.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 (file)
index 0000000..ad868ef
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- 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.
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 64
diff --git a/usr/klibc/arch/ia64/crt0.S b/usr/klibc/arch/ia64/crt0.S
new file mode 100644 (file)
index 0000000..722276e
--- /dev/null
@@ -0,0 +1,27 @@
+
+#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 */
+       movl gp = @gprel(0f)
+0:     mov r9 = ip
+       ;;
+       sub gp = r9, gp     /* back-compute gp value */
+
+       .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/pipe.S b/usr/klibc/arch/ia64/pipe.S
new file mode 100644 (file)
index 0000000..8ecd972
--- /dev/null
@@ -0,0 +1,29 @@
+#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
+       ;;
+(p7)   addl r14 = @ltoffx(errno), r1
+
+(p6)   st4 [r32] = r8, 4
+(p7)   addl r15 = -1, r0
+       ;;
+
+(p7)   ld8.mov r14 = [r14], errno
+(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 (file)
index 0000000..ab1cea2
--- /dev/null
@@ -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/syscall.S b/usr/klibc/arch/ia64/syscall.S
new file mode 100644 (file)
index 0000000..9929618
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# arch/ia64/syscall.S
+#
+
+#include <asm/unistd.h>
+
+       .text
+       .align  32
+       .proc   __syscall_error
+       .globl  __syscall_error
+__syscall_error:
+       addl    r2 = @ltoffx(errno),gp
+       ;;
+       ld8.mov r3 = [r2],errno
+       ;;
+       st4     [r3] = 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 (file)
index 0000000..8e686c6
--- /dev/null
@@ -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 (file)
index 0000000..7e76a71
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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
+       ;;
+       addl    r15=0,r1
+       cmp.eq  p7,p6 = -1,r10
+       ;;
+       ld8     r14=[r15]
+       ;;
+(p7)   st4     [r14]=r8
+       ;;
+(p7)   mov     r8=-1
+       br.ret.sptk.many b0
+       .endp vfork
diff --git a/usr/klibc/arch/m32r/Kbuild b/usr/klibc/arch/m32r/Kbuild
new file mode 100644 (file)
index 0000000..ceb2ba0
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# klibc files for m32r
+#
+
+
+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/m32r/MCONFIG b/usr/klibc/arch/m32r/MCONFIG
new file mode 100644 (file)
index 0000000..7ca2785
--- /dev/null
@@ -0,0 +1,18 @@
+# -*- makefile -*-
+#
+# arch/m32r/MCONFIG
+#
+# Special rules for this architecture.  Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+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
+# 224 MB - normal binaries start at 0 (?)
+# (lib?)gcc on cris seems to insist on producing .init and .fini sections
+KLIBCSHAREDFLAGS     = --section-start .init=0x0e000100
diff --git a/usr/klibc/arch/m32r/crt0.S b/usr/klibc/arch/m32r/crt0.S
new file mode 100644 (file)
index 0000000..568e5d8
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# arch/m32r/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
+       .balign 4
+       .type   _start,@function
+       .globl  _start
+_start:
+       /* Save the address of the ELF argument array */
+       mv      r0, sp
+
+       /* atexit() function (assume null) */
+       xor     r1, r1
+
+       bl      __libc_init
+
+       .size _start, .-_start
diff --git a/usr/klibc/arch/m32r/setjmp.S b/usr/klibc/arch/m32r/setjmp.S
new file mode 100644 (file)
index 0000000..02a25e7
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# arch/m32r/setjmp.S
+#
+# setjmp/longjmp for the M32R architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#      r8-r15
+#
+#      Note that r14 is the return address register and
+#      r15 is the stack pointer.
+#
+
+       .text
+       .balign 4
+       .globl  setjmp
+       .type   setjmp, @function
+setjmp:
+       st      r8, @r0
+       st      r9, @+r0
+       st      r10, @+r0
+       st      r11, @+r0
+       st      r12, @+r0
+       st      r13, @+r0
+       st      r14, @+r0
+       st      r15, @+r0
+       xor     r0, r0
+       jmp     r14
+       .size   setjmp,.-setjmp
+
+       .text
+       .balign 4
+       .globl  longjmp
+       .type   longjmp, @function
+longjmp:
+       ld      r8, @r0+
+       ld      r9, @r0+
+       ld      r10, @r0+
+       ld      r11, @r0+
+       ld      r12, @r0+
+       ld      r13, @r0+
+       ld      r14, @r0+
+       ld      r15, @r0
+       mv      r0, r1
+       jmp     r14
+       .size longjmp,.-longjmp
diff --git a/usr/klibc/arch/m32r/syscall.S b/usr/klibc/arch/m32r/syscall.S
new file mode 100644 (file)
index 0000000..a20a336
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/m32r/syscall.S
+ *
+ *     r7 contains the syscall number (set by stub);
+ * r0..r3 contains arguments 0-3 per standard calling convention;
+ * r4..r5 contains arguments 4-5, but we have to get those from
+ *        the stack.
+ */
+
+       .section ".text","ax"
+       .balign 4
+       .globl  __syscall_common
+       .type   __syscall_common,@function
+__syscall_common:
+       ld      r4,@sp
+       ld      r5,@(4,sp)
+       trap    #2
+       cmpi    r0, #-4096
+       bnc     1f
+       jmp     r14
+1:
+       seth    r2,#high(errno)
+       or3     r2,r2,#low(errno)
+       neg     r1,r0
+       st      r1,@r7
+       ldi     r0,#-1
+       jmp     r14
+
+       .size   __syscall_common,.-__syscall_common
diff --git a/usr/klibc/arch/m32r/sysstub.ph b/usr/klibc/arch/m32r/sysstub.ph
new file mode 100644 (file)
index 0000000..98dfb9d
--- /dev/null
@@ -0,0 +1,25 @@
+# -*- perl -*-
+#
+# arch/m32r/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.type\t${fname},\@function\n";
+    print OUT "\t.globl\t${fname}\n";
+    print OUT "\t.balign\t4\n";
+    print OUT "${fname}:\n";
+    print OUT "\tldi\tr7,#__NR_${sname}\n";
+    print OUT "\tbra\t__syscall_common\n";
+    print OUT "\t.size ${fname},.-${fname}\n";
+    close(OUT);
+}
+
+1;
diff --git a/usr/klibc/arch/m68k/Kbuild b/usr/klibc/arch/m68k/Kbuild
new file mode 100644 (file)
index 0000000..d56ae0e
--- /dev/null
@@ -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 (file)
index 0000000..7d4615d
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- 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        = -Ttext 0xb0000000
diff --git a/usr/klibc/arch/m68k/crt0.S b/usr/klibc/arch/m68k/crt0.S
new file mode 100644 (file)
index 0000000..fbf6f13
--- /dev/null
@@ -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 (file)
index 0000000..c9a7ee3
--- /dev/null
@@ -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 (file)
index 0000000..25d8a1a
--- /dev/null
@@ -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 (file)
index 0000000..1b3591e
--- /dev/null
@@ -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 (file)
index 0000000..c909e2a
--- /dev/null
@@ -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 (file)
index 0000000..78c239d
--- /dev/null
@@ -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 (file)
index 0000000..98170a6
--- /dev/null
@@ -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 (file)
index 0000000..972e450
--- /dev/null
@@ -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 (file)
index 0000000..c6331a1
--- /dev/null
@@ -0,0 +1,15 @@
+# -*- 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
+KLIBCSHAREDFLAGS       = -T $(src)/arch/$(KLIBCARCH)/klibc.ld
diff --git a/usr/klibc/arch/mips/crt0.S b/usr/klibc/arch/mips/crt0.S
new file mode 100644 (file)
index 0000000..142d9f2
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# 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, 32, sp)
+       subu    sp, 32
+       sw      zero, 16(sp)
+
+       lui     gp, %hi(_gp)            # Initialize gp
+       addiu   gp, gp, _gp
+
+       addiu   a0, sp, 32              # Pointer to ELF entry structure
+       move    a1, v0                  # Kernel-provided atexit() pointer
+
+       jal     __libc_init
+
+       END(__start)
diff --git a/usr/klibc/arch/mips/klibc.ld b/usr/klibc/arch/mips/klibc.ld
new file mode 100644 (file)
index 0000000..5a2a7a6
--- /dev/null
@@ -0,0 +1,214 @@
+/* Linker script for klibc.so, needed because of the the damned
+   GNU ld script headers problem */
+
+ENTRY(__start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  /* 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 */
+  . = 0x00200400;
+  .interp         : { *(.interp) }
+  .reginfo        : { *(.reginfo) }
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.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.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.*)
+    }
+  .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.*)
+    }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    _ftext = . ;
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.mips16.fn.*) *(.mips16.call.*)
+  } =0
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0
+  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.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* 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(8192);
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(32 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    _fdata = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .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))
+    /* We don't want to include the .ctor section from
+       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 ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  _gp = ALIGN(16) + 0x7ff0;
+  .got            : { *(.got.plt) *(.got) }
+  /* 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.*)
+  }
+  .lit8           : { *(.lit8) }
+  .lit4           : { *(.lit4) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  _fbss = .;
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .);
+    PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .);
+    PROVIDE (___sbss_end = .);
+  }
+  .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.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 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_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) }
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/usr/klibc/arch/mips/pipe.S b/usr/klibc/arch/mips/pipe.S
new file mode 100644 (file)
index 0000000..932fc08
--- /dev/null
@@ -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 (file)
index 0000000..68eed19
--- /dev/null
@@ -0,0 +1,80 @@
+#
+# 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
+#      f20..f31
+#      fcr31
+#
+
+#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)
+       cfc1    t0,$31
+       swc1    $f20,48(a0)
+       swc1    $f21,52(a0)
+       swc1    $f22,56(a0)
+       swc1    $f23,60(a0)
+       swc1    $f24,64(a0)
+       swc1    $f25,68(a0)
+       swc1    $f26,72(a0)
+       swc1    $f27,76(a0)
+       swc1    $f28,80(a0)
+       swc1    $f29,84(a0)
+       swc1    $f30,88(a0)
+       swc1    $f31,92(a0)
+       sw      t0,96(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)
+       lw      t0, 96(a0)
+       lwc1    $f20,48(a0)
+       lwc1    $f21,52(a0)
+       lwc1    $f22,56(a0)
+       lwc1    $f23,60(a0)
+       lwc1    $f24,64(a0)
+       lwc1    $f25,68(a0)
+       lwc1    $f26,72(a0)
+       lwc1    $f27,76(a0)
+       lwc1    $f28,80(a0)
+       lwc1    $f29,84(a0)
+       lwc1    $f30,88(a0)
+       lwc1    $f31,92(a0)
+       ctc1    t0,$31
+       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 (file)
index 0000000..cca0db2
--- /dev/null
@@ -0,0 +1,15 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+       .set noreorder
+
+LEAF(__syscall_common)
+       syscall
+        beqz    a3, 1f
+       # sw is actually two instructions; the first one goes
+       # in the branch delay slot
+       # XXX: Break this up manually; as it is now it generates warnings.
+        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 (file)
index 0000000..3689529
--- /dev/null
@@ -0,0 +1,29 @@
+# -*- 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 "\t.set noreorder\n";
+    print OUT "\n";
+    print OUT "LEAF(${fname})\n";
+    print OUT "\tj\t__syscall_${stype}\n";
+    print OUT "\t  li\tv0, __NR_${sname}\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 (file)
index 0000000..9aa955a
--- /dev/null
@@ -0,0 +1,15 @@
+#include <machine/asm.h>
+#include <asm/unistd.h>
+
+#define CLONE_VM       0x00000100
+#define CLONE_VFORK    0x00004000
+#define SIGCHLD                18
+
+       .set noreorder
+
+LEAF(vfork)
+       li      a0, CLONE_VFORK | CLONE_VM | SIGCHLD
+       li      a1, 0
+       j       __syscall_common
+         li    v0, __NR_clone
+       END(vfork)
diff --git a/usr/klibc/arch/mips64/Kbuild b/usr/klibc/arch/mips64/Kbuild
new file mode 100644 (file)
index 0000000..970c0f8
--- /dev/null
@@ -0,0 +1,3 @@
+#
+# klibc files for mips64
+#
diff --git a/usr/klibc/arch/mips64/MCONFIG b/usr/klibc/arch/mips64/MCONFIG
new file mode 100644 (file)
index 0000000..5c50b8d
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- 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.
+#
+
+KLIBCOPTFLAGS += -Os
+KLIBCBITSIZE  = 64
diff --git a/usr/klibc/arch/parisc/Kbuild b/usr/klibc/arch/parisc/Kbuild
new file mode 100644 (file)
index 0000000..57ca5c2
--- /dev/null
@@ -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 (file)
index 0000000..628e987
--- /dev/null
@@ -0,0 +1,12 @@
+# -*- 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       = -Ttext 0x40001000
diff --git a/usr/klibc/arch/parisc/crt0.S b/usr/klibc/arch/parisc/crt0.S
new file mode 100644 (file)
index 0000000..0922446
--- /dev/null
@@ -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 (file)
index 0000000..c8d766c
--- /dev/null
@@ -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 (file)
index 0000000..0ff2a65
--- /dev/null
@@ -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 (file)
index 0000000..e2196ac
--- /dev/null
@@ -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 (file)
index 0000000..97ebc8f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * arch/parisc/vfork.S, "vfork() me harder. ugh." -- kyle
+ *
+ * %r20 contains the system call number, %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) */
+       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 (file)
index 0000000..699380f
--- /dev/null
@@ -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 (file)
index 0000000..6630df7
--- /dev/null
@@ -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     = -Ttext 0x0f800200
+
+# The kernel so far has both asm-ppc* and asm-powerpc.
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)/arch/powerpc/include
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH   = powerpc
diff --git a/usr/klibc/arch/ppc/crt0.S b/usr/klibc/arch/ppc/crt0.S
new file mode 100644 (file)
index 0000000..85b6dca
--- /dev/null
@@ -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 (file)
index 0000000..e02b7da
--- /dev/null
@@ -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 (file)
index 0000000..0a7c37c
--- /dev/null
@@ -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 (file)
index 0000000..3b3916c
--- /dev/null
@@ -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 (file)
index 0000000..a39e91f
--- /dev/null
@@ -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 (file)
index 0000000..1331e05
--- /dev/null
@@ -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     = -Ttext 0x0f000200
+
+# The kernel so far has both asm-ppc* and asm-powerpc.
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)/arch/powerpc/include
+
+# The asm include files live in asm-powerpc
+KLIBCASMARCH   = powerpc
diff --git a/usr/klibc/arch/ppc64/crt0.S b/usr/klibc/arch/ppc64/crt0.S
new file mode 100644 (file)
index 0000000..ed14534
--- /dev/null
@@ -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 (file)
index 0000000..ecf9717
--- /dev/null
@@ -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 (file)
index 0000000..a5895fe
--- /dev/null
@@ -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 (file)
index 0000000..b3f6e38
--- /dev/null
@@ -0,0 +1,44 @@
+# -*- 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}:
+#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/s390/Kbuild b/usr/klibc/arch/s390/Kbuild
new file mode 100644 (file)
index 0000000..6a8e97a
--- /dev/null
@@ -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 (file)
index 0000000..82d9a74
--- /dev/null
@@ -0,0 +1,23 @@
+# -*- 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       = -Ttext 0x40000200
diff --git a/usr/klibc/arch/s390/crt0.S b/usr/klibc/arch/s390/crt0.S
new file mode 100644 (file)
index 0000000..fd9237e
--- /dev/null
@@ -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 (file)
index 0000000..3331239
--- /dev/null
@@ -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 %b1\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 (file)
index 0000000..c36a051
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# 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     %f1,80(%r2)             # save fp registers f4 and f6
+       std     %f3,88(%r2)
+       std     %f5,96(%r2)
+       std     %f7,104(%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      %f7,104(%r1)            # restore all saved registers
+       ld      %f5,96(%r1)
+       ld      %f3,88(%r1)
+       ld      %f1,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 (file)
index 0000000..e1d201d
--- /dev/null
@@ -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 (file)
index 0000000..1ca7b6b
--- /dev/null
@@ -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 (file)
index 0000000..29b606a
--- /dev/null
@@ -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 (file)
index 0000000..665abb2
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- 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       = -Ttext 0x00200200
diff --git a/usr/klibc/arch/sh/crt0.S b/usr/klibc/arch/sh/crt0.S
new file mode 100644 (file)
index 0000000..7f0a649
--- /dev/null
@@ -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 (file)
index 0000000..01b055b
--- /dev/null
@@ -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 (file)
index 0000000..2552358
--- /dev/null
@@ -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 (file)
index 0000000..77245b7
--- /dev/null
@@ -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 (file)
index 0000000..0ff46dd
--- /dev/null
@@ -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 (file)
index 0000000..d013f5d
--- /dev/null
@@ -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 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 (file)
index 0000000..235ce60
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- 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        = -Ttext 0x40000100
diff --git a/usr/klibc/arch/sparc/__muldi3.S b/usr/klibc/arch/sparc/__muldi3.S
new file mode 100644 (file)
index 0000000..e53848a
--- /dev/null
@@ -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 (file)
index 0000000..63db188
--- /dev/null
@@ -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 (file)
index 0000000..0220b01
--- /dev/null
@@ -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 (file)
index 0000000..aa4171d
--- /dev/null
@@ -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 (file)
index 0000000..a8abf3c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * arch/sparc/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#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
+       sethi   %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..038ea78
--- /dev/null
@@ -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/smul.S b/usr/klibc/arch/sparc/smul.S
new file mode 100644 (file)
index 0000000..544ff6e
--- /dev/null
@@ -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 (file)
index 0000000..c0273f7
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * arch/sparc/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+       .globl  __syscall_common
+       .type   __syscall_common,#function
+               .align  4
+__syscall_common:
+       t       0x10
+       bcc     1f
+         sethi %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..a66c76e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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
+ */
+
+       .globl  __syscall_forkish
+       .type   __syscall_forkish,#function
+               .align  4
+__syscall_forkish:
+       t       0x10
+       sub     %o1, 1, %o1
+       bcc,a   1f
+         and   %o0, %o1, %o0
+       sethi   %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..d8cedb5
--- /dev/null
@@ -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 (file)
index 0000000..6a7193d
--- /dev/null
@@ -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 (file)
index 0000000..2854f69
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# klibc files for sparc64
+#
+
+klib-y := pipe.o setjmp.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 (file)
index 0000000..bd6f004
--- /dev/null
@@ -0,0 +1,21 @@
+# -*- 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 -mptr64 -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       = -Ttext 0x80000200
diff --git a/usr/klibc/arch/sparc64/crt0.S b/usr/klibc/arch/sparc64/crt0.S
new file mode 100644 (file)
index 0000000..5faee7c
--- /dev/null
@@ -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 (file)
index 0000000..c63b20f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * arch/sparc64/pipe.S
+ *
+ * The pipe system call are special on sparc[64]:
+ * they return the two file descriptors in %o0 and %o1.
+ */
+
+#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
+       sethi   %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..75a6a68
--- /dev/null
@@ -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/syscall.S b/usr/klibc/arch/sparc64/syscall.S
new file mode 100644 (file)
index 0000000..7ab9d95
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/sparc64/syscall.S
+ *
+ * Common system-call stub; %g1 already set to syscall number
+ */
+
+       .globl  __syscall_common
+       .type   __syscall_common,#function
+               .align  4
+__syscall_common:
+       t       0x6d
+       bcc     %xcc, 1f
+         sethi %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..2eed659
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+
+       .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
+       sethi   %hi(errno), %g4
+       or      %g4, %lo(errno), %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 (file)
index 0000000..deeb88c
--- /dev/null
@@ -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 (file)
index 0000000..3f69c5b
--- /dev/null
@@ -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 (file)
index 0000000..4b1a33a
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- 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 \
+               -falign-functions=1 -falign-jumps=1 -falign-loops=1
+ifeq ($(DEBUG),y)
+KLIBCOPTFLAGS     += -g
+else
+KLIBCOPTFLAGS     += -fno-asynchronous-unwind-tables
+endif
+KLIBCBITSIZE      = 64
+KLIBCLDFLAGS      = -m elf_x86_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
+# 2 MB - normal binaries start at 4 MB
+#
+# Recent binutils use max-page-size=0x200000 by default, which pushes
+# klibc.so data over the 4 MB mark, overlapping the executable.
+# Revert to the old max-page-size=0x100000 value.
+KLIBCSHAREDFLAGS     = -Ttext 0x00200200 -z max-page-size=0x100000
+
+# Asm includes for x86_64 are in the merged x86 tree
+KLIBCARCHINCFLAGS = -I$(KLIBCKERNELOBJ)/arch/x86/include
diff --git a/usr/klibc/arch/x86_64/crt0.S b/usr/klibc/arch/x86_64/crt0.S
new file mode 100644 (file)
index 0000000..6a5f335
--- /dev/null
@@ -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 (file)
index 0000000..45f547b
--- /dev/null
@@ -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 (file)
index 0000000..46a5a0b
--- /dev/null
@@ -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 (file)
index 0000000..1797797
--- /dev/null
@@ -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 (file)
index 0000000..e2d797b
--- /dev/null
@@ -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 (file)
index 0000000..e1c8090
--- /dev/null
@@ -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 (file)
index 0000000..a3f5f00
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * asprintf.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int asprintf(char **bufp, const char *format, ...)
+{
+       va_list ap, ap1;
+       int rv;
+       int bytes;
+       char *p;
+
+       va_start(ap, format);
+       va_copy(ap1, ap);
+
+       bytes = vsnprintf(NULL, 0, format, ap1) + 1;
+       va_end(ap1);
+
+       *bufp = p = malloc(bytes);
+       if (!p)
+               return -1;
+
+       rv = vsnprintf(p, bytes, format, ap);
+       va_end(ap);
+
+       return rv;
+}
diff --git a/usr/klibc/assert.c b/usr/klibc/assert.c
new file mode 100644 (file)
index 0000000..cca4129
--- /dev/null
@@ -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 (file)
index 0000000..af1b461
--- /dev/null
@@ -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 (file)
index 0000000..5018689
--- /dev/null
@@ -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 (file)
index 0000000..a6ec0bf
--- /dev/null
@@ -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 (file)
index 0000000..e65484e
--- /dev/null
@@ -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 (file)
index 0000000..25df79e
--- /dev/null
@@ -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 (file)
index 0000000..c013bb4
--- /dev/null
@@ -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 (file)
index 0000000..df0bb7b
--- /dev/null
@@ -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 (file)
index 0000000..3d78d2c
--- /dev/null
@@ -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 (file)
index 0000000..1c8b07f
--- /dev/null
@@ -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 (file)
index 0000000..aa1c1ff
--- /dev/null
@@ -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 (file)
index 0000000..53dcc6b
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * calloc.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* FIXME: This should look for multiplication overflow */
+
+void *calloc(size_t nmemb, size_t size)
+{
+       return zalloc(nmemb * size);
+}
diff --git a/usr/klibc/chmod.c b/usr/klibc/chmod.c
new file mode 100644 (file)
index 0000000..b5129e6
--- /dev/null
@@ -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 (file)
index 0000000..089cfc5
--- /dev/null
@@ -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 (file)
index 0000000..7c2435e
--- /dev/null
@@ -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/closelog.c b/usr/klibc/closelog.c
new file mode 100644 (file)
index 0000000..0437710
--- /dev/null
@@ -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 (file)
index 0000000..b503bca
--- /dev/null
@@ -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 (file)
index 0000000..f9e247d
--- /dev/null
@@ -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 (file)
index 0000000..57af18b
--- /dev/null
@@ -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 (file)
index 0000000..8f2effe
--- /dev/null
@@ -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 (file)
index 0000000..6a974d5
--- /dev/null
@@ -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 (file)
index 0000000..7728550
--- /dev/null
@@ -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 (file)
index 0000000..81db804
--- /dev/null
@@ -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 (file)
index 0000000..41a39d9
--- /dev/null
@@ -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 (file)
index 0000000..e5b83d1
--- /dev/null
@@ -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 (file)
index 0000000..9e179ae
--- /dev/null
@@ -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 (file)
index 0000000..9c6a351
--- /dev/null
@@ -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 (file)
index 0000000..36b5258
--- /dev/null
@@ -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 (file)
index 0000000..aed06c8
--- /dev/null
@@ -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 (file)
index 0000000..70a139b
--- /dev/null
@@ -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 (file)
index 0000000..ab89c1f
--- /dev/null
@@ -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 (file)
index 0000000..24ca72b
--- /dev/null
@@ -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 (file)
index 0000000..15763f7
--- /dev/null
@@ -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 (file)
index 0000000..deb566a
--- /dev/null
@@ -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 (file)
index 0000000..61b88dd
--- /dev/null
@@ -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 (file)
index 0000000..67e2171
--- /dev/null
@@ -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 (file)
index 0000000..419c317
--- /dev/null
@@ -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 (file)
index 0000000..ae70be8
--- /dev/null
@@ -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 (file)
index 0000000..76b70df
--- /dev/null
@@ -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 (file)
index 0000000..4581113
--- /dev/null
@@ -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 (file)
index 0000000..b073988
--- /dev/null
@@ -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 (file)
index 0000000..65c9aa4
--- /dev/null
@@ -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 (file)
index 0000000..fef972f
--- /dev/null
@@ -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 (file)
index 0000000..6894e79
--- /dev/null
@@ -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 (file)
index 0000000..7d8e2bc
--- /dev/null
@@ -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 (file)
index 0000000..0b844f2
--- /dev/null
@@ -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 (file)
index 0000000..2368b07
--- /dev/null
@@ -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 (file)
index 0000000..dbf742c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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;
+}
diff --git a/usr/klibc/fnmatch.c b/usr/klibc/fnmatch.c
new file mode 100644 (file)
index 0000000..5d0a25f
--- /dev/null
@@ -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 (file)
index 0000000..b07486e
--- /dev/null
@@ -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 (file)
index 0000000..8403923
--- /dev/null
@@ -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 (file)
index 0000000..386d86c
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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;
+}
diff --git a/usr/klibc/fputs.c b/usr/klibc/fputs.c
new file mode 100644 (file)
index 0000000..fb240d6
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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);
+}
diff --git a/usr/klibc/fread2.c b/usr/klibc/fread2.c
new file mode 100644 (file)
index 0000000..7dca56b
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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;
+}
diff --git a/usr/klibc/fstatfs.c b/usr/klibc/fstatfs.c
new file mode 100644 (file)
index 0000000..614f2ec
--- /dev/null
@@ -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/fwrite2.c b/usr/klibc/fwrite2.c
new file mode 100644 (file)
index 0000000..cebc017
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * 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;
+}
diff --git a/usr/klibc/getcwd.c b/usr/klibc/getcwd.c
new file mode 100644 (file)
index 0000000..22ec812
--- /dev/null
@@ -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 (file)
index 0000000..218ff0b
--- /dev/null
@@ -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 (file)
index 0000000..3a4ae5e
--- /dev/null
@@ -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 (file)
index 0000000..120edd9
--- /dev/null
@@ -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 (file)
index 0000000..8af27f3
--- /dev/null
@@ -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 (file)
index 0000000..806735d
--- /dev/null
@@ -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 (file)
index 0000000..e3d064b
--- /dev/null
@@ -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 (file)
index 0000000..b20b17a
--- /dev/null
@@ -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 (file)
index 0000000..01d6e06
--- /dev/null
@@ -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/getpt.c b/usr/klibc/getpt.c
new file mode 100644 (file)
index 0000000..8d2a536
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * getpt.c
+ *
+ * GNU extension to the standard Unix98 pty suite
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+
+int getpt(void)
+{
+       return open("/dev/ptmx", O_RDWR | O_NOCTTY);
+}
diff --git a/usr/klibc/globals.c b/usr/klibc/globals.c
new file mode 100644 (file)
index 0000000..72ae91f
--- /dev/null
@@ -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 (file)
index 0000000..e22c1c2
--- /dev/null
@@ -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 (file)
index 0000000..ba086c3
--- /dev/null
@@ -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 (file)
index 0000000..beceeea
--- /dev/null
@@ -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 (file)
index 0000000..6dbf057
--- /dev/null
@@ -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 (file)
index 0000000..106fb45
--- /dev/null
@@ -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 (file)
index 0000000..19fe16e
--- /dev/null
@@ -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/interp.S b/usr/klibc/interp.S
new file mode 100644 (file)
index 0000000..4b15cfb
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# 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
diff --git a/usr/klibc/isatty.c b/usr/klibc/isatty.c
new file mode 100644 (file)
index 0000000..2359479
--- /dev/null
@@ -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 (file)
index 0000000..8e2b3ac
--- /dev/null
@@ -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 (file)
index 0000000..9a9e1e1
--- /dev/null
@@ -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 (file)
index 0000000..c54d022
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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"
+
+/* 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);
+extern void __libc_archinit(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 (file)
index 0000000..95937f0
--- /dev/null
@@ -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 (file)
index 0000000..14e6d18
--- /dev/null
@@ -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 (file)
index 0000000..ebb11f0
--- /dev/null
@@ -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 (file)
index 0000000..973fe63
--- /dev/null
@@ -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 (file)
index 0000000..35420f5
--- /dev/null
@@ -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 (file)
index 0000000..765e1f2
--- /dev/null
@@ -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 (file)
index 0000000..0e7ed98
--- /dev/null
@@ -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 (file)
index 0000000..33a21ba
--- /dev/null
@@ -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 (file)
index 0000000..5eea461
--- /dev/null
@@ -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 (file)
index 0000000..aa86112
--- /dev/null
@@ -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 (file)
index 0000000..54980f0
--- /dev/null
@@ -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 (file)
index 0000000..5635f3f
--- /dev/null
@@ -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 (file)
index 0000000..1fc754a
--- /dev/null
@@ -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 (file)
index 0000000..85e6e3c
--- /dev/null
@@ -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 (file)
index 0000000..1d4b70e
--- /dev/null
@@ -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 (file)
index 0000000..7dfcf92
--- /dev/null
@@ -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 (file)
index 0000000..f262d19
--- /dev/null
@@ -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 (file)
index 0000000..3288a33
--- /dev/null
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_lstat
+
+int lstat(const char *path, struct stat *buf)
+{
+       return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+}
+
+#endif  /* __NR_lstat  */
diff --git a/usr/klibc/makeerrlist.pl b/usr/klibc/makeerrlist.pl
new file mode 100644 (file)
index 0000000..43c747c
--- /dev/null
@@ -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 (file)
index 0000000..413b733
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <assert.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;
+
+       /* 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
+       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) {
+               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 (file)
index 0000000..af97a3f
--- /dev/null
@@ -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 (file)
index 0000000..83d02c9
--- /dev/null
@@ -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 (file)
index 0000000..f1947fb
--- /dev/null
@@ -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 (file)
index 0000000..3ce9941
--- /dev/null
@@ -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 (file)
index 0000000..5ce206d
--- /dev/null
@@ -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 (file)
index 0000000..8b5faa0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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 > n || !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 (file)
index 0000000..a398cd8
--- /dev/null
@@ -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 (file)
index 0000000..ff6d711
--- /dev/null
@@ -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 (file)
index 0000000..aa00b5b
--- /dev/null
@@ -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 (file)
index 0000000..b32315c
--- /dev/null
@@ -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 (file)
index 0000000..27673e3
--- /dev/null
@@ -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 (file)
index 0000000..727505f
--- /dev/null
@@ -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 (file)
index 0000000..2c427ca
--- /dev/null
@@ -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 (file)
index 0000000..e3b73cc
--- /dev/null
@@ -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/nice.c b/usr/klibc/nice.c
new file mode 100644 (file)
index 0000000..e6e99ac
--- /dev/null
@@ -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 (file)
index 0000000..cb3532b
--- /dev/null
@@ -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 (file)
index 0000000..ba7e71c
--- /dev/null
@@ -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 (file)
index 0000000..15a96b5
--- /dev/null
@@ -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 (file)
index 0000000..5305c3d
--- /dev/null
@@ -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/open_cloexec.c b/usr/klibc/open_cloexec.c
new file mode 100644 (file)
index 0000000..e30b09d
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * open_cloexec.c
+ *
+ * A quick hack to do an open() and set the cloexec flag
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+
+int open_cloexec(const char *path, int flags, mode_t mode)
+{
+       int fd = open(path, flags, mode);
+
+       if (fd >= 0)
+               fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+       return fd;
+}
diff --git a/usr/klibc/openat.c b/usr/klibc/openat.c
new file mode 100644 (file)
index 0000000..8e5baa0
--- /dev/null
@@ -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 (file)
index 0000000..cec97a8
--- /dev/null
@@ -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 (file)
index 0000000..3177057
--- /dev/null
@@ -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 (file)
index 0000000..dfaed9e
--- /dev/null
@@ -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 (file)
index 0000000..f539b99
--- /dev/null
@@ -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/posix_openpt.c b/usr/klibc/posix_openpt.c
new file mode 100644 (file)
index 0000000..794ca46
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * posix_openpt.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+
+int posix_openpt(int oflag)
+{
+       return open("/dev/ptmx", oflag);
+}
diff --git a/usr/klibc/ppoll.c b/usr/klibc/ppoll.c
new file mode 100644 (file)
index 0000000..5e20a89
--- /dev/null
@@ -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/printf.c b/usr/klibc/printf.c
new file mode 100644 (file)
index 0000000..02bdba0
--- /dev/null
@@ -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 (file)
index 0000000..1bb6852
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * pselect.c
+ */
+
+#include <sys/select.h>
+#include <sys/syscall.h>
+
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+
+/* Don't need to do anything here; use syscall stub directly */
+
+#elif defined(__NR_pselect7)
+
+__extern int __pselect7(int, fd_set *, fd_set *, fd_set *,
+                       const struct timespec *, const sigset_t *, size_t);
+
+int pselect(int n, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
+           const struct timespec *timeout, const sigset_t * sigmask)
+{
+       return __pselect7(n, readfds, writefds, exceptfds,
+                         timeout, sigmask, sizeof *sigmask);
+}
+
+#elif defined(__NR_pselect6)
+
+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);
+}
+
+#endif
diff --git a/usr/klibc/pty.c b/usr/klibc/pty.c
new file mode 100644 (file)
index 0000000..7fcb2ba
--- /dev/null
@@ -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 (file)
index 0000000..e2224ca
--- /dev/null
@@ -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 (file)
index 0000000..5059ecb
--- /dev/null
@@ -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 (file)
index 0000000..27e16e2
--- /dev/null
@@ -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/qsort.c b/usr/klibc/qsort.c
new file mode 100644 (file)
index 0000000..4c189fc
--- /dev/null
@@ -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 (file)
index 0000000..3b9d23d
--- /dev/null
@@ -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 (file)
index 0000000..8134c92
--- /dev/null
@@ -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 (file)
index 0000000..0e67442
--- /dev/null
@@ -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 (file)
index 0000000..14a2f2f
--- /dev/null
@@ -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/reboot.c b/usr/klibc/reboot.c
new file mode 100644 (file)
index 0000000..5795dc3
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * reboot.c
+ */
+
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <sys/syscall.h>
+
+/* This provides the one-argument glibc-ish version of reboot.
+   The full four-argument system call is available as __reboot(). */
+
+int reboot(int flag)
+{
+       return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, flag, NULL);
+}
diff --git a/usr/klibc/recv.c b/usr/klibc/recv.c
new file mode 100644 (file)
index 0000000..0baa00a
--- /dev/null
@@ -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 (file)
index 0000000..9088204
--- /dev/null
@@ -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 (file)
index 0000000..587c26f
--- /dev/null
@@ -0,0 +1,11 @@
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifndef __NR_rename
+
+int rename(const char *oldpath, const char *newpath)
+{
+       return renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
+}
+
+#endif /* __NR_rename */
diff --git a/usr/klibc/rmdir.c b/usr/klibc/rmdir.c
new file mode 100644 (file)
index 0000000..94ae5f2
--- /dev/null
@@ -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 (file)
index 0000000..4896ce0
--- /dev/null
@@ -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 (file)
index 0000000..9b95980
--- /dev/null
@@ -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 (file)
index 0000000..ccdf183
--- /dev/null
@@ -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 (file)
index 0000000..7af28fe
--- /dev/null
@@ -0,0 +1,34 @@
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <sys/syscall.h>
+
+#if !defined(__NR_select) && !defined(__NR__newselect)
+
+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, &ts, NULL);
+
+       if (timeout) {
+               timeout->tv_sec = ts.tv_sec;
+               timeout->tv_usec = ts.tv_nsec / 1000;
+       }
+
+       return result;
+}
+
+#endif
diff --git a/usr/klibc/send.c b/usr/klibc/send.c
new file mode 100644 (file)
index 0000000..a867dd1
--- /dev/null
@@ -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 (file)
index 0000000..6af966f
--- /dev/null
@@ -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 (file)
index 0000000..45a7aad
--- /dev/null
@@ -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 (file)
index 0000000..18dddb1
--- /dev/null
@@ -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 (file)
index 0000000..d23e141
--- /dev/null
@@ -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 (file)
index 0000000..75bbcc7
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * setpgrp.c
+ */
+
+#include <unistd.h>
+
+int setpgrp(void)
+{
+       return setpgid(0, 0);
+}
diff --git a/usr/klibc/sha1hash.c b/usr/klibc/sha1hash.c
new file mode 100644 (file)
index 0000000..c29eebf
--- /dev/null
@@ -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/shm_open.c b/usr/klibc/shm_open.c
new file mode 100644 (file)
index 0000000..8fe93aa
--- /dev/null
@@ -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_cloexec(path, oflag, mode);
+}
diff --git a/usr/klibc/shm_unlink.c b/usr/klibc/shm_unlink.c
new file mode 100644 (file)
index 0000000..94a98a0
--- /dev/null
@@ -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 (file)
index 0000000..21a799c
--- /dev/null
@@ -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 (file)
index 0000000..19a8a54
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern void __sigreturn(void);
+__extern int __sigaction(int, const struct sigaction *, struct sigaction *);
+#ifdef __sparc__
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
+                           void (*)(void), size_t);
+#elif defined(__alpha__)
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
+                           size_t, void *);
+#else
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *,
+                           size_t);
+#endif
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+       int rv;
+
+#if _KLIBC_NEEDS_SA_RESTORER
+       struct sigaction sa;
+
+       if (act && !(act->sa_flags & SA_RESTORER)) {
+               sa = *act;
+               act = &sa;
+
+               /* The kernel can't be trusted to have a valid default
+                  restorer */
+               sa.sa_flags |= SA_RESTORER;
+               sa.sa_restorer = &__sigreturn;
+       }
+#endif
+
+#if _KLIBC_USE_RT_SIG
+# ifdef __sparc__
+       {
+               void (*restorer)(void);
+               restorer = (act && act->sa_flags & SA_RESTORER)
+                       ? (void (*)(void))((uintptr_t)act->sa_restorer - 8)
+                       : NULL;
+               rv = __rt_sigaction(sig, act, oact, restorer, sizeof(sigset_t));
+       }
+# elif defined(__alpha__)
+       rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t), NULL);
+# else
+       rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t));
+# endif
+#else
+       rv = __sigaction(sig, act, oact);
+#endif
+
+#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 (file)
index 0000000..d690049
--- /dev/null
@@ -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 (file)
index 0000000..31042cb
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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)
+{
+       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 (file)
index 0000000..26fd3e9
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * sigpending.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__extern int __rt_sigpending(sigset_t *, size_t);
+
+int sigpending(sigset_t * set)
+{
+       return __rt_sigpending(set, sizeof(sigset_t));
+}
+
+#endif
diff --git a/usr/klibc/sigprocmask.c b/usr/klibc/sigprocmask.c
new file mode 100644 (file)
index 0000000..ea12c13
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * sigprocmask.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__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));
+}
+
+#endif
diff --git a/usr/klibc/sigsuspend.c b/usr/klibc/sigsuspend.c
new file mode 100644 (file)
index 0000000..26a521a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * sigsuspend.c
+ */
+
+#include <signal.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+#include <klibc/havesyscall.h>
+
+#if _KLIBC_USE_RT_SIG
+
+__extern int __rt_sigsuspend(const sigset_t *, size_t);
+
+int sigsuspend(const sigset_t * mask)
+{
+       return __rt_sigsuspend(mask, sizeof *mask);
+}
+
+#else
+
+extern int __sigsuspend_s(sigset_t);
+extern int __sigsuspend_xxs(int, int, sigset_t);
+
+int
+sigsuspend(const sigset_t *maskp)
+{
+#ifdef _KLIBC_HAVE_SYSCALL___sigsuspend_s
+       return __sigsuspend_s(*maskp);
+#elif defined(_KLIBC_HAVE_SYSCALL___sigsuspend_xxs)
+       return __sigsuspend_xxs(0, 0, *maskp);
+#else
+# error "Unknown sigsuspend implementation"
+#endif
+}
+
+#endif
diff --git a/usr/klibc/sleep.c b/usr/klibc/sleep.c
new file mode 100644 (file)
index 0000000..47dfd29
--- /dev/null
@@ -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 (file)
index 0000000..713b3cd
--- /dev/null
@@ -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 (file)
index 0000000..3dac096
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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";
+
+       if ( $arch eq 'i386' ) {
+           open(OUT, "> ${outputdir}/${name}.S")
+               or die "$0: Cannot open ${outputdir}/${name}.S\n";
+
+           print OUT "#include <sys/socketcalls.h>\n";
+           print OUT "\n";
+           print OUT "\t.text\n";
+           print OUT "\t.align 4\n";
+           print OUT "\t.globl ${name}\n";
+           print OUT "\t.type  ${name},\@function\n";
+           print OUT "${name}:\n";
+           print OUT "\tpushl  \$SYS_\U${name}\n";
+           print OUT "\tjmp    __socketcall_common\n";
+           print OUT "\t.size ${name},.-${name}\n";
+           close(OUT);
+       } else {
+           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 || !defined(__NR_${name})\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 (file)
index 0000000..67da0d1
--- /dev/null
@@ -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 (file)
index 0000000..a974a88
--- /dev/null
@@ -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 (file)
index 0000000..9c4b11f
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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>
+#include <sys/socketcalls.h>
diff --git a/usr/klibc/sprintf.c b/usr/klibc/sprintf.c
new file mode 100644 (file)
index 0000000..c6d8758
--- /dev/null
@@ -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 (file)
index 0000000..e1c9567
--- /dev/null
@@ -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 (file)
index 0000000..f53b276
--- /dev/null
@@ -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 (file)
index 0000000..65063b0
--- /dev/null
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_stat
+
+int stat(const char *path, struct stat *buf)
+{
+       return fstatat(AT_FDCWD, path, buf, 0);
+}
+
+#endif /* __NR_stat */
diff --git a/usr/klibc/statfs.c b/usr/klibc/statfs.c
new file mode 100644 (file)
index 0000000..b8b8700
--- /dev/null
@@ -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/fclose.c b/usr/klibc/stdio/fclose.c
new file mode 100644 (file)
index 0000000..756de43
--- /dev/null
@@ -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 (file)
index 0000000..cdc35cc
--- /dev/null
@@ -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 (file)
index 0000000..590b1c5
--- /dev/null
@@ -0,0 +1,7 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int feof(FILE *__f)
+{
+       return __f->_IO_eof;
+}
diff --git a/usr/klibc/stdio/ferror.c b/usr/klibc/stdio/ferror.c
new file mode 100644 (file)
index 0000000..8b36e44
--- /dev/null
@@ -0,0 +1,7 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int ferror(FILE *__f)
+{
+       return __f->_IO_error;
+}
diff --git a/usr/klibc/stdio/fflush.c b/usr/klibc/stdio/fflush.c
new file mode 100644 (file)
index 0000000..dfccd24
--- /dev/null
@@ -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;
+       }
+}
+
+
diff --git a/usr/klibc/stdio/fgetc.c b/usr/klibc/stdio/fgetc.c
new file mode 100644 (file)
index 0000000..a0e8650
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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;
+       }
+}
diff --git a/usr/klibc/stdio/fileno.c b/usr/klibc/stdio/fileno.c
new file mode 100644 (file)
index 0000000..b5a1016
--- /dev/null
@@ -0,0 +1,7 @@
+#define __NO_STDIO_INLINES
+#include "stdioint.h"
+
+int fileno(FILE *__f)
+{
+       return __f->_IO_fileno;
+}
diff --git a/usr/klibc/stdio/fopen.c b/usr/klibc/stdio/fopen.c
new file mode 100644 (file)
index 0000000..cf098df
--- /dev/null
@@ -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 (file)
index 0000000..b099426
--- /dev/null
@@ -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 (file)
index 0000000..e35f85e
--- /dev/null
@@ -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 (file)
index 0000000..cb1202d
--- /dev/null
@@ -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 (file)
index 0000000..71ee75c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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)
+                       if (__fflush(f))
+                               break;
+
+               if (f->obytes == 0 && count >= f->bufsiz) {
+                       /*
+                        * The buffer is empty and the write is large,
+                        * so bypass the 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 (file)
index 0000000..fb7cd5a
--- /dev/null
@@ -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 (file)
index 0000000..724c657
--- /dev/null
@@ -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 (file)
index 0000000..fe328ac
--- /dev/null
@@ -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 (file)
index 0000000..ee1f28b
--- /dev/null
@@ -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 (file)
index 0000000..6c5b673
--- /dev/null
@@ -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 (file)
index 0000000..6040cc4
--- /dev/null
@@ -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 (file)
index 0000000..3ab9f5a
--- /dev/null
@@ -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 (file)
index 0000000..aa656cf
--- /dev/null
@@ -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 (file)
index 0000000..35fd38c
--- /dev/null
@@ -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 (file)
index 0000000..905b51d
--- /dev/null
@@ -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 (file)
index 0000000..fed0e49
--- /dev/null
@@ -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 (file)
index 0000000..80c3375
--- /dev/null
@@ -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 (file)
index 0000000..51c72d8
--- /dev/null
@@ -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 (file)
index 0000000..86526a5
--- /dev/null
@@ -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 (file)
index 0000000..0551935
--- /dev/null
@@ -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 (file)
index 0000000..beb026c
--- /dev/null
@@ -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 (file)
index 0000000..5235545
--- /dev/null
@@ -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 (file)
index 0000000..fffc118
--- /dev/null
@@ -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 (file)
index 0000000..20eaa8b
--- /dev/null
@@ -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 (file)
index 0000000..1678f4b
--- /dev/null
@@ -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 (file)
index 0000000..179d9e5
--- /dev/null
@@ -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 (file)
index 0000000..56dddad
--- /dev/null
@@ -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 (file)
index 0000000..300dbba
--- /dev/null
@@ -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 (file)
index 0000000..e36d37e
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * strrchr.c
+ */
+
+#include <string.h>
+#include <klibc/compiler.h>
+
+char *strrchr(const char *s, int c)
+{
+       const char *found = NULL;
+
+       while (*s) {
+               if (*s == (char)c)
+                       found = s;
+               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 (file)
index 0000000..44e76bd
--- /dev/null
@@ -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 (file)
index 0000000..e345e9c
--- /dev/null
@@ -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 (file)
index 0000000..828fa2b
--- /dev/null
@@ -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 (file)
index 0000000..8850858
--- /dev/null
@@ -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 (file)
index 0000000..0cdd088
--- /dev/null
@@ -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 (file)
index 0000000..6b169a1
--- /dev/null
@@ -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 (file)
index 0000000..695d516
--- /dev/null
@@ -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 (file)
index 0000000..9efc8b9
--- /dev/null
@@ -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 (file)
index 0000000..a9428c7
--- /dev/null
@@ -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 (file)
index 0000000..b426bf8
--- /dev/null
@@ -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 (file)
index 0000000..280d4bc
--- /dev/null
@@ -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 (file)
index 0000000..0624082
--- /dev/null
@@ -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 (file)
index 0000000..3189aaa
--- /dev/null
@@ -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 (file)
index 0000000..83c14e9
--- /dev/null
@@ -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 (file)
index 0000000..a379710
--- /dev/null
@@ -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 (file)
index 0000000..c22e7c7
--- /dev/null
@@ -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 (file)
index 0000000..99bdbff
--- /dev/null
@@ -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 (file)
index 0000000..ce56ff2
--- /dev/null
@@ -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 (file)
index 0000000..080394f
--- /dev/null
@@ -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 (file)
index 0000000..3ff0222
--- /dev/null
@@ -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 (file)
index 0000000..d255e6e
--- /dev/null
@@ -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 (file)
index 0000000..2430b9b
--- /dev/null
@@ -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 $< $@
+
+$(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 (file)
index 0000000..78f8858
--- /dev/null
@@ -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/syslog.c b/usr/klibc/syslog.c
new file mode 100644 (file)
index 0000000..4052eaa
--- /dev/null
@@ -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 (file)
index 0000000..13e9fbe
--- /dev/null
@@ -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 (file)
index 0000000..beee7d7
--- /dev/null
@@ -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 (file)
index 0000000..c7ca531
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# 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
+
+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
+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
+strtoimax.shared-y     := strtoimax.o
+strtotime.shared-y     := strtotime.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 (file)
index 0000000..5253d51
--- /dev/null
@@ -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 (file)
index 0000000..30cc900
--- /dev/null
@@ -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 (file)
index 0000000..ff8d58e
--- /dev/null
@@ -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 (file)
index 0000000..6c019b7
--- /dev/null
@@ -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 (file)
index 0000000..58619d1
--- /dev/null
@@ -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 (file)
index 0000000..1ae946a
--- /dev/null
@@ -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 (file)
index 0000000..3f859bd
--- /dev/null
@@ -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 (file)
index 0000000..c3c4447
--- /dev/null
@@ -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 (file)
index 0000000..c4e7f54
--- /dev/null
@@ -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 (file)
index 0000000..2ae184e
--- /dev/null
@@ -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 (file)
index 0000000..1845073
--- /dev/null
@@ -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/memstrtest.c b/usr/klibc/tests/memstrtest.c
new file mode 100644 (file)
index 0000000..8d473fb
--- /dev/null
@@ -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 (file)
index 0000000..c999d11
--- /dev/null
@@ -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 (file)
index 0000000..ae9072e
--- /dev/null
@@ -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 (file)
index 0000000..eac04e8
--- /dev/null
@@ -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 (file)
index 0000000..8be7b3d
--- /dev/null
@@ -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 (file)
index 0000000..0e49721
--- /dev/null
@@ -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 (file)
index 0000000..a7f8eed
--- /dev/null
@@ -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 (file)
index 0000000..ba08112
--- /dev/null
@@ -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 (file)
index 0000000..1b07199
--- /dev/null
@@ -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 (file)
index 0000000..fd9cb1c
--- /dev/null
@@ -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 (file)
index 0000000..90086e4
--- /dev/null
@@ -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 (file)
index 0000000..ec62e33
--- /dev/null
@@ -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 (file)
index 0000000..48814f9
--- /dev/null
@@ -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 (file)
index 0000000..c06aae4
--- /dev/null
@@ -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 (file)
index 0000000..4410833
--- /dev/null
@@ -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 (file)
index 0000000..0ac8051
--- /dev/null
@@ -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 (file)
index 0000000..895c730
--- /dev/null
@@ -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 (file)
index 0000000..14df0cd
--- /dev/null
@@ -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/strtoimax.c b/usr/klibc/tests/strtoimax.c
new file mode 100644 (file)
index 0000000..318f2d4
--- /dev/null
@@ -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 (file)
index 0000000..16d2e0f
--- /dev/null
@@ -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/testrand48.c b/usr/klibc/tests/testrand48.c
new file mode 100644 (file)
index 0000000..26868c7
--- /dev/null
@@ -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 (file)
index 0000000..7120bda
--- /dev/null
@@ -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 (file)
index 0000000..7adc036
--- /dev/null
@@ -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 (file)
index 0000000..a0c366b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * time.c
+ */
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_time
+
+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;
+}
+
+#endif
diff --git a/usr/klibc/umount.c b/usr/klibc/umount.c
new file mode 100644 (file)
index 0000000..d31a300
--- /dev/null
@@ -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 (file)
index 0000000..6dfe66c
--- /dev/null
@@ -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 (file)
index 0000000..c5cc95a
--- /dev/null
@@ -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 (file)
index 0000000..549aec3
--- /dev/null
@@ -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 (file)
index 0000000..ac184bc
--- /dev/null
@@ -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 (file)
index 0000000..3a95688
--- /dev/null
@@ -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 (file)
index 0000000..cbe706a
--- /dev/null
@@ -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 (file)
index 0000000..e936d54
--- /dev/null
@@ -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 (file)
index 0000000..ee2e99a
--- /dev/null
@@ -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 (file)
index 0000000..dda093f
--- /dev/null
@@ -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 (file)
index 0000000..67b1533
--- /dev/null
@@ -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 (file)
index 0000000..cb8f50a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * utime.c
+ */
+
+#include <utime.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_utime
+
+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);
+}
+
+#endif
diff --git a/usr/klibc/utimes.c b/usr/klibc/utimes.c
new file mode 100644 (file)
index 0000000..fd378a6
--- /dev/null
@@ -0,0 +1,20 @@
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_utimes
+
+int utimes(const char *file, const struct timeval tvp[2])
+{
+       struct timespec ts[2];
+
+       if (tvp) {
+               ts->tv_sec = tvp->tv_sec;
+               ts->tv_nsec = tvp->tv_usec * 1000;
+       }
+
+       return utimensat(AT_FDCWD, file, &ts[0], 0);
+}
+
+#endif /* __NR_utimes */
diff --git a/usr/klibc/vasprintf.c b/usr/klibc/vasprintf.c
new file mode 100644 (file)
index 0000000..cdc302f
--- /dev/null
@@ -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 (file)
index 0000000..2165f8f
--- /dev/null
@@ -0,0 +1 @@
+2.0.4
diff --git a/usr/klibc/vfork.c b/usr/klibc/vfork.c
new file mode 100644 (file)
index 0000000..f2b1a85
--- /dev/null
@@ -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 (file)
index 0000000..6f5663b
--- /dev/null
@@ -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 (file)
index 0000000..d6bfeaf
--- /dev/null
@@ -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 (file)
index 0000000..26be710
--- /dev/null
@@ -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 (file)
index 0000000..51f5d87
--- /dev/null
@@ -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 (file)
index 0000000..b8f068c
--- /dev/null
@@ -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 (file)
index 0000000..73bb1a2
--- /dev/null
@@ -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 (file)
index 0000000..1f35414
--- /dev/null
@@ -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 (file)
index 0000000..a157122
--- /dev/null
@@ -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 (file)
index 0000000..0a5e823
--- /dev/null
@@ -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 (file)
index 0000000..441d910
--- /dev/null
@@ -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 (file)
index 0000000..0587e59
--- /dev/null
@@ -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 (file)
index 0000000..f2e1bf2
--- /dev/null
@@ -0,0 +1,8 @@
+# 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
diff --git a/usr/klibc/zlib/README b/usr/klibc/zlib/README
new file mode 100644 (file)
index 0000000..758cc50
--- /dev/null
@@ -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 (file)
index 0000000..22e1151
--- /dev/null
@@ -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 (file)
index 0000000..b022dde
--- /dev/null
@@ -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 (file)
index 0000000..4f48f55
--- /dev/null
@@ -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 (file)
index 0000000..f658a9e
--- /dev/null
@@ -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 (file)
index 0000000..8053b61
--- /dev/null
@@ -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 (file)
index 0000000..7a9b03d
--- /dev/null
@@ -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 (file)
index 0000000..0a37d70
--- /dev/null
@@ -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 (file)
index 0000000..0116ea3
--- /dev/null
@@ -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 (file)
index 0000000..455dbc9
--- /dev/null
@@ -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 (file)
index 0000000..bbee92e
--- /dev/null
@@ -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 (file)
index 0000000..1e88d2d
--- /dev/null
@@ -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 (file)
index 0000000..75ed4b5
--- /dev/null
@@ -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 (file)
index 0000000..792fdee
--- /dev/null
@@ -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 (file)
index 0000000..07bd3e7
--- /dev/null
@@ -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 (file)
index 0000000..8a9c13f
--- /dev/null
@@ -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 (file)
index 0000000..b1104c8
--- /dev/null
@@ -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 (file)
index 0000000..82578a1
--- /dev/null
@@ -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 (file)
index 0000000..aadfa16
--- /dev/null
@@ -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 (file)
index 0000000..debee43
--- /dev/null
@@ -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 (file)
index 0000000..c7575eb
--- /dev/null
@@ -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 (file)
index 0000000..90b8162
--- /dev/null
@@ -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 (file)
index 0000000..f9ce953
--- /dev/null
@@ -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 (file)
index 0000000..42f52b1
--- /dev/null
@@ -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 (file)
index 0000000..05aa794
--- /dev/null
@@ -0,0 +1,76 @@
+#
+# 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 += 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/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 shared/reboot shared/poweroff
+
+$(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 only install the shared binaries
+install-y := $(shared-y) shared/reboot shared/poweroff
diff --git a/usr/utils/cat.c b/usr/utils/cat.c
new file mode 100644 (file)
index 0000000..7465148
--- /dev/null
@@ -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 (file)
index 0000000..bc1b94f
--- /dev/null
@@ -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 (file)
index 0000000..cb61679
--- /dev/null
@@ -0,0 +1,1061 @@
+/* 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 <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((unsigned int)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;
+       }
+       /* 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);
+}
+
+/* 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 (file)
index 0000000..706b8c3
--- /dev/null
@@ -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 (file)
index 0000000..1960713
--- /dev/null
@@ -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 (file)
index 0000000..2c3243a
--- /dev/null
@@ -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 (file)
index 0000000..48f7f43
--- /dev/null
@@ -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 (file)
index 0000000..364f603
--- /dev/null
@@ -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 (file)
index 0000000..eed0a46
--- /dev/null
@@ -0,0 +1,58 @@
+#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]\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;
+
+       /* 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 && **argv == '-')
+               switch (*++*argv) {
+               case 'f':
+                       break; /* -f assumed */
+               case 'n':
+                       do_sync = 0;
+                       break;
+               default:
+                       usage();
+               }
+       if (*argv)
+               usage(); /* any args == error */
+
+       if (do_sync)
+               sync();
+       reboot(LINUX_REBOOT_CMD_CAD_OFF); /* Enable CTRL+ALT+DEL */
+       if (!reboot(cmd)) {
+               /* 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/kill.c b/usr/utils/kill.c
new file mode 100644 (file)
index 0000000..188f1b5
--- /dev/null
@@ -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 (file)
index 0000000..e826eb8
--- /dev/null
@@ -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/loop.h b/usr/utils/loop.h
new file mode 100644 (file)
index 0000000..9abc287
--- /dev/null
@@ -0,0 +1,49 @@
+#define LO_CRYPT_NONE  0
+#define LO_CRYPT_XOR   1
+#define LO_CRYPT_DES   2
+#define LO_CRYPT_CRYPTOAPI 18
+
+#define LOOP_SET_FD            0x4C00
+#define LOOP_CLR_FD            0x4C01
+#define LOOP_SET_STATUS                0x4C02
+#define LOOP_GET_STATUS                0x4C03
+#define LOOP_SET_STATUS64      0x4C04
+#define LOOP_GET_STATUS64      0x4C05
+
+#define LO_NAME_SIZE   64
+#define LO_KEY_SIZE    32
+
+struct loop_info {
+       int             lo_number;
+       dev_t           lo_device;
+       unsigned long   lo_inode;
+       dev_t           lo_rdevice;
+       int             lo_offset;
+       int             lo_encrypt_type;
+       int             lo_encrypt_key_size;
+       int             lo_flags;
+       char            lo_name[LO_NAME_SIZE];
+       unsigned char   lo_encrypt_key[LO_KEY_SIZE];
+       unsigned long   lo_init[2];
+       char            reserved[4];
+};
+
+/*
+ * Where to get __u8, __u32, __u64? Let us use unsigned char/int/long long
+ * and get punished when someone comes with 128-bit long longs.
+ */
+struct loop_info64 {
+       unsigned long long      lo_device;
+       unsigned long long      lo_inode;
+       unsigned long long      lo_rdevice;
+       unsigned long long      lo_offset;
+       unsigned long long      lo_sizelimit; /* bytes, 0 == max available */
+       unsigned int            lo_number;
+       unsigned int            lo_encrypt_type;
+       unsigned int            lo_encrypt_key_size;
+       unsigned int            lo_flags;
+       char                    lo_file_name[LO_NAME_SIZE];
+       char                    lo_crypt_name[LO_NAME_SIZE];
+       char                    lo_encrypt_key[LO_KEY_SIZE];
+       unsigned long long      lo_init[2];
+};
diff --git a/usr/utils/losetup.c b/usr/utils/losetup.c
new file mode 100644 (file)
index 0000000..1788741
--- /dev/null
@@ -0,0 +1,484 @@
+/* Originally from Ted's losetup.c */
+
+#define LOOPMAJOR      7
+
+/*
+ * losetup.c - setup and control loop devices
+ */
+
+#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 "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 loop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info)
+{
+       memset(info, 0, sizeof(*info));
+       info->lo_number = info64->lo_number;
+       info->lo_device = info64->lo_device;
+       info->lo_inode = info64->lo_inode;
+       info->lo_rdevice = info64->lo_rdevice;
+       info->lo_offset = info64->lo_offset;
+       info->lo_encrypt_type = info64->lo_encrypt_type;
+       info->lo_encrypt_key_size = info64->lo_encrypt_key_size;
+       info->lo_flags = info64->lo_flags;
+       info->lo_init[0] = info64->lo_init[0];
+       info->lo_init[1] = info64->lo_init[1];
+       if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
+               memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
+       else
+               memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE);
+       memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
+
+       /* error in case values were truncated */
+       if (info->lo_device != info64->lo_device ||
+                       info->lo_rdevice != info64->lo_rdevice ||
+                       info->lo_inode != info64->lo_inode ||
+                       info->lo_offset != info64->lo_offset)
+               return -EOVERFLOW;
+
+       return 0;
+}
+
+
+static int show_loop(char *device)
+{
+       struct loop_info loopinfo;
+       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]) {
+                       char *e = 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;
+       }
+
+       if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0) {
+               printf ("%s: [%04x]:%ld (%s)",
+                       device, loopinfo.lo_device, loopinfo.lo_inode,
+                       loopinfo.lo_name);
+
+               if (loopinfo.lo_offset)
+                       printf(", offset %d", loopinfo.lo_offset);
+
+               if (loopinfo.lo_encrypt_type)
+                       printf(", encryption type %d\n",
+                              loopinfo.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)
+{
+       /* Just creating a device, say in /tmp, is probably a bad idea -
+          people might have problems with backup or so.
+          So, we just try /dev/loop[0-7]. */
+       char dev[20];
+       char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
+       int i, j, fd, somedev = 0, someloop = 0, permission = 0;
+       struct stat statbuf;
+       struct loop_info loopinfo;
+
+       for (j = 0; j < SIZE(loop_formats); j++) {
+               for(i = 0; i < 256; i++) {
+                       sprintf(dev, loop_formats[j], i);
+                       if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
+                               somedev++;
+                               fd = open (dev, O_RDONLY);
+                               if (fd >= 0) {
+                                       if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
+                                               someloop++;             /* in use */
+                                       else if (errno == ENXIO) {
+                                               close (fd);
+                                               return xstrdup(dev);/* probably free */
+                                       }
+                                       close (fd);
+                               } else if (errno == EACCES)
+                                       permission++;
+
+                               continue;/* continue trying as long as devices exist */
+                       }
+                       break;
+               }
+       }
+
+       if (!somedev)
+               error("%s: could not find any device /dev/loop#", progname);
+       else if (!someloop && permission)
+               error("%s: no permission to look at /dev/loop#", progname);
+       else if (!someloop)
+               error(
+                   "%s: Could not find any loop device. Maybe this kernel "
+                   "does not know\n"
+                   "       about the loop device? (If so, recompile or "
+                   "`modprobe loop'.)", progname);
+       else
+               error("%s: could not find any free loop device", progname);
+       return 0;
+}
+
+/*
+ * 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(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(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(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) {
+               struct loop_info loopinfo;
+               int errsv = errno;
+
+               i = loop_info64_to_old(&loopinfo64, &loopinfo);
+               if (i) {
+                       errno = errsv;
+                       perror("ioctl: LOOP_SET_STATUS64");
+               } else {
+                       i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
+                       if (i)
+                               perror("ioctl: LOOP_SET_STATUS");
+               }
+               memset(&loopinfo, 0, sizeof(loopinfo));
+       }
+       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 (file)
index 0000000..9677bc0
--- /dev/null
@@ -0,0 +1,225 @@
+#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, 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 = readlink(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;
+       struct dirent *dent;
+       struct stat st;
+
+       if (chdir(path) == -1) {
+               perror(path);
+               exit(1);
+       }
+
+       dir = opendir(path);
+       if (dir == NULL) {
+               perror(path);
+               exit(1);
+       }
+
+       while ((dent = readdir(dir)) != NULL) {
+               if (lstat(dent->d_name, &st)) {
+                       perror(dent->d_name);
+                       exit(1);
+               }
+               (preformat) ?
+                       do_preformat(&st) :
+                       do_stat(&st, 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, argv[i]);
+       }
+
+       return 0;
+}
diff --git a/usr/utils/minips.c b/usr/utils/minips.c
new file mode 100644 (file)
index 0000000..f48505f
--- /dev/null
@@ -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 (file)
index 0000000..af241ef
--- /dev/null
@@ -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 (file)
index 0000000..5a758b2
--- /dev/null
@@ -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 (file)
index 0000000..fa7ac7a
--- /dev/null
@@ -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 (file)
index 0000000..ab3cb71
--- /dev/null
@@ -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 (file)
index 0000000..05d1729
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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])
+                       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 (file)
index 0000000..cf47cae
--- /dev/null
@@ -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 (file)
index 0000000..e3f38ed
--- /dev/null
@@ -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 (file)
index 0000000..93a04af
--- /dev/null
@@ -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 (file)
index 0000000..41b2ea0
--- /dev/null
@@ -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 (file)
index 0000000..4e3cfcb
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+const char *progname;
+
+static __noreturn usage(void)
+{
+       fprintf(stderr, "Usage: %s link...\n", progname);
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       const char *name;
+       char link_name[PATH_MAX];
+       int rv;
+       int i;
+
+       progname = *argv++;
+
+       if (argc < 2)
+               usage();
+
+       while ((name = *argv++)) {
+               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 (file)
index 0000000..991cdbe
--- /dev/null
@@ -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 (file)
index 0000000..de3093c
--- /dev/null
@@ -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 (file)
index 0000000..31dbf45
--- /dev/null
@@ -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 (file)
index 0000000..41275f7
--- /dev/null
@@ -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 (file)
index 0000000..6ea4dbe
--- /dev/null
@@ -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;
+}