Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9e7fa1a87 |
39
.gitignore
vendored
39
.gitignore
vendored
@@ -1,39 +0,0 @@
|
||||
cscope.*
|
||||
*.swap
|
||||
.*.sw[po]
|
||||
.sw[po]
|
||||
*~
|
||||
*.orig
|
||||
*.diff
|
||||
*.patch
|
||||
*.rej
|
||||
*.[1-9].gz
|
||||
*.o
|
||||
*.[psS]o
|
||||
*.a
|
||||
*.d
|
||||
.depend
|
||||
nbsdsrc/*
|
||||
tools/revision
|
||||
TAGS
|
||||
tags
|
||||
GPATH
|
||||
GRTAGS
|
||||
GSYMS
|
||||
GTAGS
|
||||
\#*#
|
||||
CVS
|
||||
!/.gitignore
|
||||
.gitignore
|
||||
.svn
|
||||
minix-port.patch
|
||||
*.worldstone.log
|
||||
.worldstone*
|
||||
usr.bin/mdocml/man/*.7
|
||||
etc/passwd
|
||||
etc/pwd.db
|
||||
etc/spwd.db
|
||||
tools/image
|
||||
tools/kernel
|
||||
share/zoneinfo/builddir
|
||||
lib/libc/compat__*
|
||||
10
LICENSE
Normal file → Executable file
10
LICENSE
Normal file → Executable file
@@ -50,13 +50,3 @@ observe the conditions of the GPL with respect to this software. As
|
||||
clearly stated in Article 2 of the GPL, when GPL and nonGPL software are
|
||||
distributed together on the same medium, this aggregation does not cause
|
||||
the license of either part to apply to the other part.
|
||||
|
||||
|
||||
Acknowledgements
|
||||
|
||||
This product includes software developed by the University of
|
||||
California, Berkeley and its contributors.
|
||||
|
||||
This product includes software developed by Softweyr LLC, the
|
||||
University of California, Berkeley, and its contributors.
|
||||
|
||||
|
||||
129
Makefile
Normal file → Executable file
129
Makefile
Normal file → Executable file
@@ -1,8 +1,6 @@
|
||||
# Master Makefile to compile everything in /usr/src except the system.
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
MAKE=make
|
||||
MAKE = exec make -$(MAKEFLAGS)
|
||||
|
||||
usage:
|
||||
@echo ""
|
||||
@@ -10,13 +8,13 @@ usage:
|
||||
@echo "Root privileges are required for some actions."
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make world # Compile everything (libraries & commands)"
|
||||
@echo " make includes # Install include files from src/"
|
||||
@echo " make libraries # Compile and install libraries"
|
||||
@echo " make commands # Compile all, commands, but don't install"
|
||||
@echo " make install # Compile and install commands"
|
||||
@echo " make gnu-includes # Install include files for GCC"
|
||||
@echo " make clean # Remove all compiler results"
|
||||
@echo " make world # Compile everything (libraries & commands)"
|
||||
@echo " make includes # Install include files from src/"
|
||||
@echo " make libraries # Compile and install libraries"
|
||||
@echo " make cmds # Compile all, commands, but don't install"
|
||||
@echo " make install # Compile and install commands"
|
||||
@echo " make depend # Generate required .depend files"
|
||||
@echo " make clean # Remove all compiler results"
|
||||
@echo ""
|
||||
@echo "Run 'make' in tools/ to create a new MINIX configuration."
|
||||
@echo ""
|
||||
@@ -29,96 +27,45 @@ usage:
|
||||
# 'make install' target.
|
||||
#
|
||||
# etcfiles has to be done first.
|
||||
world: mkfiles etcfiles includes libraries dep-all install etcforce
|
||||
|
||||
mkfiles:
|
||||
make -C share/mk install
|
||||
world: includes depend libraries cmds install postinstall
|
||||
|
||||
includes:
|
||||
$(MAKE) -C include includes
|
||||
$(MAKE) -C lib includes NBSD_LIBC=yes
|
||||
cd include && $(MAKE) install gcc
|
||||
|
||||
MKHEADERSS=/usr/pkg/gcc*/libexec/gcc/*/*/install-tools/mkheaders
|
||||
gnu-includes: includes
|
||||
SHELL=/bin/sh; for d in $(MKHEADERSS); do if [ -f $$d ] ; then sh -e $$d ; fi; done
|
||||
libraries:
|
||||
cd lib && $(MAKE) all install
|
||||
|
||||
libraries: includes
|
||||
$(MAKE) -C lib dependall install
|
||||
cmds:
|
||||
if [ -f commands/Makefile ] ; then cd commands && $(MAKE) all; fi
|
||||
|
||||
commands: includes libraries
|
||||
$(MAKE) -C commands all
|
||||
$(MAKE) -C bin all
|
||||
$(MAKE) -C sbin all
|
||||
$(MAKE) -C usr.bin all
|
||||
$(MAKE) -C libexec all
|
||||
$(MAKE) -C usr.sbin all
|
||||
install::
|
||||
if [ -f commands/Makefile ] ; then cd commands && $(MAKE) install; fi
|
||||
|
||||
dep-all:
|
||||
$(MAKE) -C sys dependall
|
||||
$(MAKE) -C commands dependall
|
||||
$(MAKE) -C bin dependall
|
||||
$(MAKE) -C sbin dependall
|
||||
$(MAKE) -C usr.bin dependall
|
||||
$(MAKE) -C libexec dependall
|
||||
$(MAKE) -C usr.sbin dependall
|
||||
$(MAKE) -C kernel dependall
|
||||
$(MAKE) -C servers dependall
|
||||
$(MAKE) -C drivers dependall
|
||||
depend::
|
||||
mkdep kernel
|
||||
mkdep servers
|
||||
mkdep drivers
|
||||
cd kernel && $(MAKE) $@
|
||||
cd servers && $(MAKE) $@
|
||||
cd drivers && $(MAKE) $@
|
||||
|
||||
etcfiles:
|
||||
$(MAKE) -C etc install
|
||||
|
||||
etcforce:
|
||||
$(MAKE) -C etc installforce
|
||||
clean::
|
||||
cd lib && $(MAKE) $@
|
||||
test ! -f commands/Makefile || { cd commands && $(MAKE) $@; }
|
||||
|
||||
all:
|
||||
$(MAKE) -C sys all
|
||||
$(MAKE) -C commands all
|
||||
$(MAKE) -C bin all
|
||||
$(MAKE) -C sbin all
|
||||
$(MAKE) -C usr.bin all
|
||||
$(MAKE) -C libexec all
|
||||
$(MAKE) -C usr.sbin all
|
||||
$(MAKE) -C tools all
|
||||
etcfiles::
|
||||
cd etc && $(MAKE) install
|
||||
|
||||
install:
|
||||
$(MAKE) -C sys install
|
||||
$(MAKE) -C libexec install
|
||||
$(MAKE) -C man install makedb
|
||||
$(MAKE) -C commands install
|
||||
$(MAKE) -C bin install
|
||||
$(MAKE) -C sbin install
|
||||
$(MAKE) -C usr.bin install
|
||||
$(MAKE) -C usr.sbin install
|
||||
$(MAKE) -C servers install
|
||||
$(MAKE) -C share install
|
||||
$(MAKE) -C tools install
|
||||
clean::
|
||||
cd test && $(MAKE) $@
|
||||
|
||||
clean: mkfiles
|
||||
$(MAKE) -C sys clean
|
||||
$(MAKE) -C commands clean
|
||||
$(MAKE) -C bin clean
|
||||
$(MAKE) -C sbin clean
|
||||
$(MAKE) -C usr.bin clean
|
||||
$(MAKE) -C libexec clean
|
||||
$(MAKE) -C usr.sbin clean
|
||||
$(MAKE) -C share clean
|
||||
$(MAKE) -C tools clean
|
||||
$(MAKE) -C lib clean
|
||||
$(MAKE) -C test clean
|
||||
all install clean::
|
||||
cd boot && $(MAKE) $@
|
||||
cd man && $(MAKE) $@ # First manpages, then commands
|
||||
test ! -f commands/Makefile || { cd commands && $(MAKE) $@; }
|
||||
cd tools && $(MAKE) $@
|
||||
cd servers && $(MAKE) $@
|
||||
|
||||
cleandepend: mkfiles
|
||||
$(MAKE) -C lib cleandepend
|
||||
$(MAKE) -C sys cleandepend
|
||||
$(MAKE) -C commands cleandepend
|
||||
$(MAKE) -C bin cleandepend
|
||||
$(MAKE) -C sbin cleandepend
|
||||
$(MAKE) -C usr.bin cleandepend
|
||||
$(MAKE) -C libexec cleandepend
|
||||
$(MAKE) -C usr.sbin cleandepend
|
||||
$(MAKE) -C tools cleandepend
|
||||
|
||||
# Warn usage change
|
||||
elf-libraries:
|
||||
echo "That target is just libraries now."
|
||||
false
|
||||
postinstall:
|
||||
cd etc && $(MAKE) $@
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# Makefile for the benchmarks.
|
||||
|
||||
all::
|
||||
chmod 755 run
|
||||
|
||||
all clean::
|
||||
for b in *bench*; do cd $$b && $(MAKE) $@; done
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
make
|
||||
|
||||
BENCHDIR=/usr/local/benchmarks
|
||||
|
||||
basebenchmarks=`echo *bench*`
|
||||
|
||||
if [ -d $BENCHDIR ]
|
||||
then packagebenchmarks=`(cd $BENCHDIR && echo *bench*)`
|
||||
fi
|
||||
|
||||
runbench() {
|
||||
bench=$1
|
||||
out="Results/$bench.`date +%Y%m%d.%H%M%S`"
|
||||
if [ -d $bench ]
|
||||
then dir=$bench
|
||||
fi
|
||||
if [ -d $BENCHDIR/$bench ]
|
||||
then dir=$BENCHDIR/$bench
|
||||
fi
|
||||
clear
|
||||
echo "Running $dir."
|
||||
echo "Saving output to $out."
|
||||
echo ""
|
||||
( cd $dir && sh run.sh 2>&1 ) | tee $out
|
||||
}
|
||||
|
||||
clear
|
||||
n=1
|
||||
for b in $basebenchmarks $packagebenchmarks
|
||||
do echo "$n. $b"
|
||||
eval "n$n=$b"
|
||||
n=`expr $n + 1`
|
||||
done
|
||||
echo
|
||||
echo -n "Run which benchmark or 'all'? "
|
||||
read bench
|
||||
eval var=\$n$bench
|
||||
if [ "$bench" = all ]
|
||||
then for b in $basebenchmarks $packagebenchmarks
|
||||
do runbench $b
|
||||
done
|
||||
else if [ -d "$var" -o -d "$BENCHDIR/$var" ]
|
||||
then runbench $var
|
||||
else echo "Unknown benchmark $var."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -1,246 +0,0 @@
|
||||
##############################################################################
|
||||
# UnixBench v5.1.1
|
||||
# Based on The BYTE UNIX Benchmarks - Release 3
|
||||
# Module: Makefile SID: 3.9 5/15/91 19:30:15
|
||||
#
|
||||
##############################################################################
|
||||
# Bug reports, patches, comments, suggestions should be sent to:
|
||||
# David C Niemi <niemi@tux.org>
|
||||
#
|
||||
# Original Contacts at Byte Magazine:
|
||||
# Ben Smith or Tom Yager at BYTE Magazine
|
||||
# bensmith@bytepb.byte.com tyager@bytepb.byte.com
|
||||
#
|
||||
##############################################################################
|
||||
# Modification Log: 7/28/89 cleaned out workload files
|
||||
# 4/17/90 added routines for installing from shar mess
|
||||
# 7/23/90 added compile for dhrystone version 2.1
|
||||
# (this is not part of Run file. still use old)
|
||||
# removed HZ from everything but dhry.
|
||||
# HZ is read from the environment, if not
|
||||
# there, you must define it in this file
|
||||
# 10/30/90 moved new dhrystone into standard set
|
||||
# new pgms (dhry included) run for a specified
|
||||
# time rather than specified number of loops
|
||||
# 4/5/91 cleaned out files not needed for
|
||||
# release 3 -- added release 3 files -ben
|
||||
# 10/22/97 added compiler options for strict ANSI C
|
||||
# checking for gcc and DEC's cc on
|
||||
# Digital Unix 4.x (kahn@zk3.dec.com)
|
||||
# 09/26/07 changes for UnixBench 5.0
|
||||
# 09/30/07 adding ubgears, GRAPHIC_TESTS switch
|
||||
# 10/14/07 adding large.txt
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# CONFIGURATION
|
||||
##############################################################################
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
# GRAPHICS TESTS: Uncomment the definition of "GRAPHIC_TESTS" to enable
|
||||
# the building of the graphics benchmarks. This will require the
|
||||
# X11 libraries on your system.
|
||||
#
|
||||
# Comment the line out to disable these tests.
|
||||
# GRAPHIC_TESTS = defined
|
||||
|
||||
# Set "GL_LIBS" to the libraries needed to link a GL program.
|
||||
GL_LIBS = -lGL -lXext -lX11
|
||||
|
||||
# OPTIMISATION SETTINGS:
|
||||
|
||||
## Very generic
|
||||
OPTON = -O
|
||||
|
||||
## For Linux 486/Pentium, GCC 2.7.x and 2.8.x
|
||||
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \
|
||||
# -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2
|
||||
|
||||
## For Linux, GCC previous to 2.7.0
|
||||
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math -m486
|
||||
|
||||
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -fforce-mem -ffast-math \
|
||||
# -m386 -malign-loops=1 -malign-jumps=1 -malign-functions=1
|
||||
|
||||
## For Solaris 2, or general-purpose GCC 2.7.x
|
||||
#OPTON = -O2 -fomit-frame-pointer -fforce-addr -ffast-math -Wall
|
||||
|
||||
## For Digital Unix v4.x, with DEC cc v5.x
|
||||
#OPTON = -O4
|
||||
#CFLAGS = -DTIME -std1 -verbose -w0
|
||||
|
||||
## generic gcc CFLAGS. -DTIME must be included.
|
||||
CFLAGS += $(CPPFLAGS) -DTIME -DMINIX=1 -D_MINIX=1 -D_POSIX_SOURCE=1
|
||||
|
||||
|
||||
##############################################################################
|
||||
# END CONFIGURATION
|
||||
##############################################################################
|
||||
|
||||
|
||||
# local directories
|
||||
PROGDIR = ./pgms
|
||||
SRCDIR = ./src
|
||||
TESTDIR = ./testdir
|
||||
RESULTDIR = ./results
|
||||
TMPDIR = ./tmp
|
||||
# other directories
|
||||
INCLDIR = /usr/include
|
||||
LIBDIR = /lib
|
||||
SCRIPTS = unixbench.logo multi.sh tst.sh index.base
|
||||
SOURCES = arith.c big.c context1.c \
|
||||
dummy.c execl.c \
|
||||
fstime.c hanoi.c \
|
||||
pipe.c spawn.c \
|
||||
syscall.c looper.c timeit.c time-polling.c \
|
||||
dhry_1.c dhry_2.c dhry.h whets.c ubgears.c
|
||||
TESTS = sort.src cctest.c dc.dat large.txt
|
||||
|
||||
# ifdef GRAPHIC_TESTS
|
||||
# GRAPHIC_BINS = $(PROGDIR)/ubgears
|
||||
# else
|
||||
GRAPHIC_BINS =
|
||||
# endif
|
||||
|
||||
# Program binaries.
|
||||
BINS = $(PROGDIR)/arithoh $(PROGDIR)/register $(PROGDIR)/short \
|
||||
$(PROGDIR)/int $(PROGDIR)/long $(PROGDIR)/float $(PROGDIR)/double \
|
||||
$(PROGDIR)/hanoi $(PROGDIR)/syscall $(PROGDIR)/context1 \
|
||||
$(PROGDIR)/pipe $(PROGDIR)/spawn $(PROGDIR)/execl \
|
||||
$(PROGDIR)/dhry2 $(PROGDIR)/dhry2reg $(PROGDIR)/looper \
|
||||
$(PROGDIR)/fstime $(PROGDIR)/whetstone-double $(GRAPHIC_BINS)
|
||||
## These compile only on some platforms...
|
||||
# $(PROGDIR)/poll $(PROGDIR)/poll2 $(PROGDIR)/select
|
||||
|
||||
# Required non-binary files.
|
||||
REQD = $(BINS) $(PROGDIR)/unixbench.logo \
|
||||
$(PROGDIR)/multi.sh $(PROGDIR)/tst.sh $(PROGDIR)/index.base \
|
||||
$(PROGDIR)/gfx-x11 \
|
||||
$(TESTDIR)/sort.src $(TESTDIR)/cctest.c $(TESTDIR)/dc.dat \
|
||||
$(TESTDIR)/large.txt
|
||||
|
||||
# ######################### the big ALL ############################
|
||||
all: distr programs
|
||||
## Ick!!! What is this about??? How about let's not chmod everything bogusly.
|
||||
# @chmod 744 * $(SRCDIR)/* $(PROGDIR)/* $(TESTDIR)/* $(DOCDIR)/*
|
||||
|
||||
# ####################### a check for Run ######################
|
||||
check: $(REQD)
|
||||
make all
|
||||
# ##############################################################
|
||||
# distribute the files out to subdirectories if they are in this one
|
||||
distr:
|
||||
@echo "Checking distribution of files"
|
||||
# scripts
|
||||
@if test ! -d $(PROGDIR) \
|
||||
; then \
|
||||
mkdir $(PROGDIR) \
|
||||
; mv $(SCRIPTS) $(PROGDIR) \
|
||||
; else \
|
||||
echo "$(PROGDIR) exists" \
|
||||
; fi
|
||||
# C sources
|
||||
@if test ! -d $(SRCDIR) \
|
||||
; then \
|
||||
mkdir $(SRCDIR) \
|
||||
; mv $(SOURCES) $(SRCDIR) \
|
||||
; else \
|
||||
echo "$(SRCDIR) exists" \
|
||||
; fi
|
||||
# test data
|
||||
@if test ! -d $(TESTDIR) \
|
||||
; then \
|
||||
mkdir $(TESTDIR) \
|
||||
; mv $(TESTS) $(TESTDIR) \
|
||||
; else \
|
||||
echo "$(TESTDIR) exists" \
|
||||
; fi
|
||||
# temporary work directory
|
||||
@if test ! -d $(TMPDIR) \
|
||||
; then \
|
||||
mkdir $(TMPDIR) \
|
||||
; else \
|
||||
echo "$(TMPDIR) exists" \
|
||||
; fi
|
||||
# directory for results
|
||||
@if test ! -d $(RESULTDIR) \
|
||||
; then \
|
||||
mkdir $(RESULTDIR) \
|
||||
; else \
|
||||
echo "$(RESULTDIR) exists" \
|
||||
; fi
|
||||
|
||||
programs: $(BINS)
|
||||
|
||||
# Individual programs
|
||||
$(PROGDIR)/arithoh: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/arithoh ${CFLAGS} ${OPTON} -Darithoh $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/register: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/register ${CFLAGS} ${OPTON} -Ddatum='register int' $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/short: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/short ${CFLAGS} ${OPTON} -Ddatum=short $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/int: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/int ${CFLAGS} ${OPTON} -Ddatum=int $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/long: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/long ${CFLAGS} ${OPTON} -Ddatum=long $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/float: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/float ${CFLAGS} ${OPTON} -Ddatum=float $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/double: $(SRCDIR)/arith.c
|
||||
$(CC) -o $(PROGDIR)/double ${CFLAGS} ${OPTON} -Ddatum=double $(SRCDIR)/arith.c
|
||||
$(PROGDIR)/whetstone-double: $(SRCDIR)/whets.c
|
||||
$(CC) -o $(PROGDIR)/whetstone-double ${CFLAGS} ${OPTON} -DDP -DUNIX -DUNIXBENCH $(SRCDIR)/whets.c -lm
|
||||
$(PROGDIR)/hanoi: $(SRCDIR)/hanoi.c
|
||||
$(CC) -o $(PROGDIR)/hanoi ${CFLAGS} ${OPTON} $(SRCDIR)/hanoi.c
|
||||
|
||||
$(PROGDIR)/poll: $(SRCDIR)/time-polling.c
|
||||
$(CC) -DHAS_POLL -DUNIXBENCH -o $(PROGDIR)/poll ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
|
||||
|
||||
$(PROGDIR)/poll2: $(SRCDIR)/time-polling.c
|
||||
$(CC) -DHAS_POLL2 -DUNIXBENCH -o $(PROGDIR)/poll2 ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
|
||||
|
||||
$(PROGDIR)/select: $(SRCDIR)/time-polling.c
|
||||
$(CC) -DHAS_SELECT -DUNIXBENCH -o $(PROGDIR)/select ${CFLAGS} ${OPTON} $(SRCDIR)/time-polling.c
|
||||
|
||||
$(PROGDIR)/fstime: $(SRCDIR)/fstime.c
|
||||
$(CC) -o $(PROGDIR)/fstime ${CFLAGS} ${OPTON} $(SRCDIR)/fstime.c
|
||||
|
||||
$(PROGDIR)/syscall: $(SRCDIR)/syscall.c
|
||||
$(CC) -o $(PROGDIR)/syscall ${CFLAGS} ${OPTON} $(SRCDIR)/syscall.c
|
||||
$(PROGDIR)/context1: $(SRCDIR)/context1.c
|
||||
$(CC) -o $(PROGDIR)/context1 ${CFLAGS} ${OPTON} $(SRCDIR)/context1.c
|
||||
$(PROGDIR)/pipe: $(SRCDIR)/pipe.c
|
||||
$(CC) -o $(PROGDIR)/pipe ${CFLAGS} ${OPTON} $(SRCDIR)/pipe.c
|
||||
$(PROGDIR)/spawn: $(SRCDIR)/spawn.c
|
||||
$(CC) -o $(PROGDIR)/spawn ${CFLAGS} ${OPTON} $(SRCDIR)/spawn.c
|
||||
$(PROGDIR)/execl: $(SRCDIR)/execl.c $(SRCDIR)/big.c
|
||||
$(CC) -o $(PROGDIR)/execl ${CFLAGS} ${OPTON} $(SRCDIR)/execl.c
|
||||
|
||||
$(PROGDIR)/dhry2: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h
|
||||
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_1.c
|
||||
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DHZ=${HZ} ${OPTON} dhry_2.c
|
||||
$(CC) -o $(PROGDIR)/dhry2 ${CFLAGS} ${OPTON} $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o
|
||||
cd $(SRCDIR); rm -f dhry_1.o dhry_2.o
|
||||
$(PROGDIR)/dhry2reg: $(SRCDIR)/dhry_1.c $(SRCDIR)/dhry_2.c $(SRCDIR)/dhry.h
|
||||
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DREG=register -DHZ=${HZ} ${OPTON} dhry_1.c
|
||||
cd $(SRCDIR); $(CC) -c ${CFLAGS} -DREG=register -DHZ=${HZ} ${OPTON} dhry_2.c
|
||||
$(CC) -o $(PROGDIR)/dhry2reg ${CFLAGS} ${OPTON} $(SRCDIR)/dhry_1.o $(SRCDIR)/dhry_2.o
|
||||
cd $(SRCDIR); rm -f dhry_1.o dhry_2.o
|
||||
|
||||
$(PROGDIR)/looper: $(SRCDIR)/looper.c
|
||||
$(CC) -o $(PROGDIR)/looper ${CFLAGS} ${OPTON} $(SRCDIR)/looper.c
|
||||
|
||||
$(PROGDIR)/ubgears: $(SRCDIR)/ubgears.c
|
||||
$(CC) -o $(PROGDIR)/ubgears ${CFLAGS} ${OPTON} $(SRCDIR)/ubgears.c $(GL_LIBS)
|
||||
|
||||
# Run the benchmarks and create the reports
|
||||
run:
|
||||
sh ./Run
|
||||
|
||||
clean:
|
||||
rm -f $(BINS) core *~ */*~
|
||||
|
||||
spotless: clean
|
||||
rm -f $(RESULTDIR)/* $(TMPDIR)/*
|
||||
|
||||
## END ##
|
||||
@@ -1,406 +0,0 @@
|
||||
Version 5.1.2 -- 2007-12-26
|
||||
|
||||
================================================================
|
||||
To use Unixbench:
|
||||
|
||||
1. UnixBench from version 5.1 on has both system and graphics tests.
|
||||
If you want to use the graphic tests, edit the Makefile and make sure
|
||||
that the line "GRAPHIC_TESTS = defined" is not commented out; then check
|
||||
that the "GL_LIBS" definition is OK for your system. Also make sure
|
||||
that the "x11perf" command is on your search path.
|
||||
|
||||
If you don't want the graphics tests, then comment out the
|
||||
"GRAPHIC_TESTS = defined" line. Note: comment it out, don't
|
||||
set it to anything.
|
||||
|
||||
2. Do "make".
|
||||
|
||||
3. Do "Run" to run the system test; "Run graphics" to run the graphics
|
||||
tests; "Run gindex" to run both.
|
||||
|
||||
You will need perl, as Run is written in perl.
|
||||
|
||||
For more information on using the tests, read "USAGE".
|
||||
|
||||
For information on adding tests into the benchmark, see "WRITING_TESTS".
|
||||
|
||||
|
||||
===================== RELEASE NOTES =====================================
|
||||
|
||||
======================== Dec 07 ==========================
|
||||
|
||||
v5.1.2
|
||||
|
||||
One big fix: if unixbench is installed in a directory whose pathname contains
|
||||
a space, it should now run (previously it failed).
|
||||
|
||||
To avoid possible clashes, the environment variables unixbench uses are now
|
||||
prefixed with "UB_". These are all optional, and for most people will be
|
||||
completely unnecessary, but if you want you can set these:
|
||||
|
||||
UB_BINDIR Directory where the test programs live.
|
||||
UB_TMPDIR Temp directory, for temp files.
|
||||
UB_RESULTDIR Directory to put results in.
|
||||
UB_TESTDIR Directory where the tests are executed.
|
||||
|
||||
And a couple of tiny fixes:
|
||||
* In pgms/tst.sh, changed "sort -n +1" to "sort -n -k 1"
|
||||
* In Makefile, made it clearer that GRAPHIC_TESTS should be commented
|
||||
out (not set to 0) to disable graphics
|
||||
Thanks to nordi for pointing these out.
|
||||
|
||||
|
||||
Ian Smith, December 26, 2007
|
||||
johantheghost at yahoo period com
|
||||
|
||||
|
||||
======================== Oct 07 ==========================
|
||||
|
||||
v5.1.1
|
||||
|
||||
It turns out that the setting of LANG is crucial to the results. This
|
||||
explains why people in different regions were seeing odd results, and also
|
||||
why runlevel 1 produced odd results -- runlevel 1 doesn't set LANG, and
|
||||
hence reverts to ASCII, whereas most people use a UTF-8 encoding, which is
|
||||
much slower in some tests (eg. shell tests).
|
||||
|
||||
So now we manually set LANG to "en_US.utf8", which is configured with the
|
||||
variable "$language". Don't change this if you want to share your results.
|
||||
We also report the language settings in use.
|
||||
|
||||
See "The Language Setting" in USAGE for more info. Thanks to nordi for
|
||||
pointing out the LANG issue.
|
||||
|
||||
I also added the "grep" and "sysexec" tests. These are non-index tests,
|
||||
and "grep" uses the system's grep, so it's not much use for comparing
|
||||
different systems. But some folks on the OpenSuSE list have been finding
|
||||
these useful. They aren't in any of the main test groups; do "Run grep
|
||||
sysexec" to run them.
|
||||
|
||||
Index Changes
|
||||
-------------
|
||||
|
||||
The setting of LANG will affect consistency with systems where this is
|
||||
not the default value. However, it should produce more consistent results
|
||||
in future.
|
||||
|
||||
|
||||
Ian Smith, October 15, 2007
|
||||
johantheghost at yahoo period com
|
||||
|
||||
|
||||
======================== Oct 07 ==========================
|
||||
|
||||
v5.1
|
||||
|
||||
The major new feature in this version is the addition of graphical
|
||||
benchmarks. Since these may not compile on all systems, you can enable/
|
||||
disable them with the GRAPHIC_TESTS variable in the Makefile.
|
||||
|
||||
As before, each test is run for 3 or 10 iterations. However, we now discard
|
||||
the worst 1/3 of the scores before averaging the remainder. The logic is
|
||||
that a glitch in the system (background process waking up, for example) may
|
||||
make one or two runs go slow, so let's discard those. Hopefully this will
|
||||
produce more consistent and repeatable results. Check the log file
|
||||
for a test run to see the discarded scores.
|
||||
|
||||
Made the tests compile and run on x86-64/Linux (fixed an execl bug passing
|
||||
int instead of pointer).
|
||||
|
||||
Also fixed some general bugs.
|
||||
|
||||
Thanks to Stefan Esser for help and testing / bug reporting.
|
||||
|
||||
Index Changes
|
||||
-------------
|
||||
|
||||
The tests are now divided into categories, and each category generates
|
||||
its own index. This keeps the graphics test results separate from
|
||||
the system tests.
|
||||
|
||||
The "graphics" test and corresponding index are new.
|
||||
|
||||
The "discard the worst scores" strategy should produce slightly higher
|
||||
test scores, but at least they should (hopefully!) be more consistent.
|
||||
The scores should not be higher than the best scores you would have got
|
||||
with 5.0, so this should not be a huge consistency issue.
|
||||
|
||||
Ian Smith, October 11, 2007
|
||||
johantheghost at yahoo period com
|
||||
|
||||
|
||||
======================== Sep 07 ==========================
|
||||
|
||||
v5.0
|
||||
|
||||
All the work I've done on this release is Linux-based, because that's
|
||||
the only Unix I have access to. I've tried to make it more OS-agnostic
|
||||
if anything; for example, it no longer has to figure out the format reported
|
||||
by /usr/bin/time. However, it's possible that portability has been damaged.
|
||||
If anyone wants to fix this, please feel free to mail me patches.
|
||||
|
||||
In particular, the analysis of the system's CPUs is done via /proc/cpuinfo.
|
||||
For systems which don't have this, please make appropriate changes in
|
||||
getCpuInfo() and getSystemInfo().
|
||||
|
||||
The big change has been to make the tests multi-CPU aware. See the
|
||||
"Multiple CPUs" section in "USAGE" for details. Other changes:
|
||||
|
||||
* Completely rewrote Run in Perl; drastically simplified the way data is
|
||||
processed. The confusing system of interlocking shell and awk scripts is
|
||||
now just one script. Various intermediate files used to store and process
|
||||
results are now replaced by Perl data structures internal to the script.
|
||||
|
||||
* Removed from the index runs file system read and write tests which were
|
||||
ignored for the index and wasted about 10 minutes per run (see fstime.c).
|
||||
The read and write tests can now be selected individually. Made fstime.c
|
||||
take parameters, so we no longer need to build 3 versions of it.
|
||||
|
||||
* Made the output file names unique; they are built from
|
||||
hostname-date-sequence.
|
||||
|
||||
* Worked on result reporting, error handling, and logging. See TESTS.
|
||||
We now generate both text and HTML reports.
|
||||
|
||||
* Removed some obsolete files.
|
||||
|
||||
Index Changes
|
||||
-------------
|
||||
|
||||
The index is still based on David Niemi's SPARCstation 20-61 (rated at 10.0),
|
||||
and the intention in the changes I've made has been to keep the tests
|
||||
unchanged, in order to maintain consistency with old result sets.
|
||||
|
||||
However, the following changes have been made to the index:
|
||||
|
||||
* The Pipe-based Context Switching test (context1) was being dropped
|
||||
from the index report in v4.1.0 due to a bug; I've put it back in.
|
||||
|
||||
* I've added shell1 to the index, to get a measure of how the shell tests
|
||||
scale with multiple CPUs (shell8 already exercises all the CPUs, even
|
||||
in single-copy mode). I made up the baseline score for this by
|
||||
extrapolation.
|
||||
|
||||
Both of these test can be dropped, if you wish, by editing the "TEST
|
||||
SPECIFICATIONS" section of Run.
|
||||
|
||||
Ian Smith, September 20, 2007
|
||||
johantheghost at yahoo period com
|
||||
|
||||
======================== Aug 97 ==========================
|
||||
|
||||
v4.1.0
|
||||
|
||||
Double precision Whetstone put in place instead of the old "double" benchmark.
|
||||
|
||||
Removal of some obsolete files.
|
||||
|
||||
"system" suite adds shell8.
|
||||
|
||||
perlbench and poll added as "exhibition" (non-index) benchmarks.
|
||||
|
||||
Incorporates several suggestions by Andre Derrick Balsa <andrewbalsa@usa.net>
|
||||
|
||||
Code cleanups to reduce compiler warnings by David C Niemi <niemi@tux.org>
|
||||
and Andy Kahn <kahn@zk3.dec.com>; Digital Unix options by Andy Kahn.
|
||||
|
||||
======================== Jun 97 ==========================
|
||||
|
||||
v4.0.1
|
||||
|
||||
Minor change to fstime.c to fix overflow problems on fast machines. Counting
|
||||
is now done in units of 256 (smallest BUFSIZE) and unsigned longs are used,
|
||||
giving another 23 dB or so of headroom ;^) Results should be virtually
|
||||
identical aside from very small rounding errors.
|
||||
|
||||
======================== Dec 95 ==========================
|
||||
|
||||
v4.0
|
||||
|
||||
Byte no longer seems to have anything to do with this benchmark, and I was
|
||||
unable to reach any of the original authors; so I have taken it upon myself
|
||||
to clean it up.
|
||||
|
||||
This is version 4. Major assumptions made in these benchmarks have changed
|
||||
since they were written, but they are nonetheless popular (particularly for
|
||||
measuring hardware for Linux). Some changes made:
|
||||
|
||||
- The biggest change is to put a lot more operating system-oriented
|
||||
tests into the index. I experimented for a while with a decibel-like
|
||||
logarithmic scale, but finally settled on using a geometric mean for
|
||||
the final index (the individual scores are a normalized, and their
|
||||
logs are averaged; the resulting value is exponentiated).
|
||||
|
||||
"George", certain SPARCstation 20-61 with 128 MB RAM, a SPARC Storage
|
||||
Array, and Solaris 2.3 is my new baseline; it is rated at 10.0 in each
|
||||
of the index scores for a final score of 10.0.
|
||||
|
||||
Overall I find the geometric averaging is a big improvement for
|
||||
avoiding the skew that was once possible (e.g. a Pentium-75 which got
|
||||
40 on the buggy version of fstime, such that fstime accounted for over
|
||||
half of its total score and hence wildly skewed its average).
|
||||
|
||||
I also expect that the new numbers look different enough from the old
|
||||
ones that no one is too likely to casually mistake them for each other.
|
||||
|
||||
I am finding new SPARCs running Solaris 2.4 getting about 15-20, and
|
||||
my 486 DX2-66 Compaq running Linux 1.3.45 got a 9.1. It got
|
||||
understandably poor scores on CPU and FPU benchmarks (a horrible
|
||||
1.8 on "double" and 1.3 on "fsdisk"); but made up for it by averaging
|
||||
over 20 on the OS-oriented benchmarks. The Pentium-75 running
|
||||
Linux gets about 20 (and it *still* runs Windows 3.1 slowly. Oh well).
|
||||
|
||||
- It is difficult to get a modern compiler to even consider making
|
||||
dhry2 without registers, short of turning off *all* optimizations.
|
||||
This is also not a terribly meaningful test, even if it were possible,
|
||||
as noone compiles without registers nowadays. Replaced this benchmark
|
||||
with dhry2reg in the index, and dropped it out of usage in general as
|
||||
it is so hard to make a legitimate one.
|
||||
|
||||
- fstime: this had some bugs when compiled on modern systems which return
|
||||
the number of bytes read/written for read(2)/write(2) calls. The code
|
||||
assumed that a negative return code was given for EOF, but most modern
|
||||
systems return 0 (certainly on SunOS 4, Solaris2, and Linux, which is
|
||||
what counts for me). The old code yielded wildly inflated read scores,
|
||||
would eat up tens of MB of disk space on fast systems, and yielded
|
||||
roughly 50% lower than normal copy scores than it should have.
|
||||
|
||||
Also, it counted partial blocks *fully*; made it count the proportional
|
||||
part of the block which was actually finished.
|
||||
|
||||
Made bigger and smaller variants of fstime which are designed to beat
|
||||
up the disk I/O and the buffer cache, respectively. Adjusted the
|
||||
sleeps so that they are short for short benchmarks.
|
||||
|
||||
- Instead of 1,2,4, and 8-shell benchmarks, went to 1, 8, and 16 to
|
||||
give a broader range of information (and to run 1 fewer test).
|
||||
The only real problem with this is that not many iterations get
|
||||
done with 16 at a time on slow systems, so there are some significant
|
||||
rounding errors; 8 therefore still used for the benchmark. There is
|
||||
also the problem that the last (uncompleted) loop is counted as a full
|
||||
loop, so it is impossible to score below 1.0 lpm (which gave my laptop
|
||||
a break). Probably redesigning Shell to do each loop a bit more
|
||||
quickly (but with less intensity) would be a good idea.
|
||||
|
||||
This benchmark appears to be very heavily influenced by the speed
|
||||
of the loader, by which shell is being used as /bin/sh, and by how
|
||||
well-compiled some of the common shell utilities like grep, sed, and
|
||||
sort are. With a consistent tool set it is also a good indicator of
|
||||
the bandwidth between main memory and the CPU (e.g. Pentia score about
|
||||
twice as high as 486es due to their 64-bit bus). Small, sometimes
|
||||
broken shells like "ash-linux" do particularly well here, while big,
|
||||
robust shells like bash do not.
|
||||
|
||||
- "dc" is a somewhat iffy benchmark, because there are two versions of
|
||||
it floating around, one being small, very fast, and buggy, and one
|
||||
being more correct but slow. It was never in the index anyway.
|
||||
|
||||
- Execl is a somewhat troubling benchmark in that it yields much higher
|
||||
scores if compiled statically. I frown on this practice because it
|
||||
distorts the scores away from reflecting how programs are really used
|
||||
(i.e. dynamically linked).
|
||||
|
||||
- Arithoh is really more an indicator of the compiler quality than of
|
||||
the computer itself. For example, GCC 2.7.x with -O2 and a few extra
|
||||
options optimizes much of it away, resulting in about a 1200% boost
|
||||
to the score. Clearly not a good one for the index.
|
||||
|
||||
I am still a bit unhappy with the variance in some of the benchmarks, most
|
||||
notably the fstime suite; and with how long it takes to run. But I think
|
||||
it gets significantly more reliable results than the older version in less
|
||||
time.
|
||||
|
||||
If anyone has ideas on how to make these benchmarks faster, lower-variance,
|
||||
or more meaningful; or has nice, new, portable benchmarks to add, don't
|
||||
hesitate to e-mail me.
|
||||
|
||||
David C Niemi <niemi@tux.org> 7 Dec 1995
|
||||
|
||||
======================== May 91 ==========================
|
||||
This is version 3. This set of programs should be able to determine if
|
||||
your system is BSD or SysV. (It uses the output format of time (1)
|
||||
to see. If you have any problems, contact me (by email,
|
||||
preferably): ben@bytepb.byte.com
|
||||
|
||||
---
|
||||
|
||||
The document doc/bench.doc describes the basic flow of the
|
||||
benchmark system. The document doc/bench3.doc describes the major
|
||||
changes in design of this version. As a user of the benchmarks,
|
||||
you should understand some of the methods that have been
|
||||
implemented to generate loop counts:
|
||||
|
||||
Tests that are compiled C code:
|
||||
The function wake_me(second, func) is included (from the file
|
||||
timeit.c). This function uses signal and alarm to set a countdown
|
||||
for the time request by the benchmark administration script
|
||||
(Run). As soon as the clock is started, the test is run with a
|
||||
counter keeping track of the number of loops that the test makes.
|
||||
When alarm sends its signal, the loop counter value is sent to stderr
|
||||
and the program terminates. Since the time resolution, signal
|
||||
trapping and other factors don't insure that the test is for the
|
||||
precise time that was requested, the test program is also run
|
||||
from the time (1) command. The real time value returned from time
|
||||
(1) is what is used in calculating the number of loops per second
|
||||
(or minute, depending on the test). As is obvious, there is some
|
||||
overhead time that is not taken into account, therefore the
|
||||
number of loops per second is not absolute. The overhead of the
|
||||
test starting and stopping and the signal and alarm calls is
|
||||
common to the overhead of real applications. If a program loads
|
||||
quickly, the number of loops per second increases; a phenomenon
|
||||
that favors systems that can load programs quickly. (Setting the
|
||||
sticky bit of the test programs is not considered fair play.)
|
||||
|
||||
Test that use existing UNIX programs or shell scripts:
|
||||
The concept is the same as that of compiled tests, except the
|
||||
alarm and signal are contained in separate compiled program,
|
||||
looper (source is looper.c). Looper uses an execvp to invoke the
|
||||
test with its arguments. Here, the overhead includes the
|
||||
invocation and execution of looper.
|
||||
|
||||
--
|
||||
|
||||
The index numbers are generated from a baseline file that is in
|
||||
pgms/index.base. You can put tests that you wish in this file.
|
||||
All you need to do is take the results/log file from your
|
||||
baseline machine, edit out the comment and blank lines, and sort
|
||||
the result (vi/ex command: 1,$!sort). The sort in necessary
|
||||
because the process of generating the index report uses join (1).
|
||||
You can regenerate the reports by running "make report."
|
||||
|
||||
--
|
||||
|
||||
========================= Jan 90 =============================
|
||||
Tom Yager has joined the effort here at BYTE; he is responsible
|
||||
for many refinements in the UNIX benchmarks.
|
||||
|
||||
The memory access tests have been deleted from the benchmarks.
|
||||
The file access tests have been reversed so that the test is run
|
||||
for a fixed time. The amount of data transfered (written, read,
|
||||
and copied) is the variable. !WARNING! This test can eat up a
|
||||
large hunk of disk space.
|
||||
|
||||
The initial line of all shell scripts has been changed from the
|
||||
SCO and XENIX form (:) to the more standard form "#! /bin/sh".
|
||||
But different systems handle shell switching differently. Check
|
||||
the documentation on your system and find out how you are
|
||||
supposed to do it. Or, simpler yet, just run the benchmarks from
|
||||
the Bourne shell. (You may need to set SHELL=/bin/sh as well.)
|
||||
|
||||
The options to Run have not been checked in a while. They may no
|
||||
longer function. Next time, I'll get back on them. There needs to
|
||||
be another option added (next time) that halts testing between
|
||||
each test. !WARNING! Some systems have caches that are not getting flushed
|
||||
before the next test or iteration is run. This can cause
|
||||
erroneous values.
|
||||
|
||||
========================= Sept 89 =============================
|
||||
The database (db) programs now have a tuneable message queue space.
|
||||
queue space. The default set in the Run script is 1024 bytes.
|
||||
Other major changes are in the format of the times. We now show
|
||||
Arithmetic and Geometric mean and standard deviation for User
|
||||
Time, System Time, and Real Time. Generally, in reporting, we
|
||||
plan on using the Real Time values with the benchs run with one
|
||||
active user (the bench user). Comments and arguments are requested.
|
||||
|
||||
contact: BIX bensmith or rick_g
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,394 +0,0 @@
|
||||
Running the Tests
|
||||
=================
|
||||
|
||||
All the tests are executed using the "Run" script in the top-level directory.
|
||||
|
||||
The simplest way to generate results is with the commmand:
|
||||
./Run
|
||||
|
||||
This will run a standard "index" test (see "The BYTE Index" below), and
|
||||
save the report in the "results" directory, with a filename like
|
||||
hostname-2007-09-23-01
|
||||
An HTML version is also saved.
|
||||
|
||||
If you want to generate both the basic system index and the graphics index,
|
||||
then do:
|
||||
./Run gindex
|
||||
|
||||
If your system has more than one CPU, the tests will be run twice -- once
|
||||
with a single copy of each test running at once, and once with N copies,
|
||||
where N is the number of CPUs. Some categories of tests, however (currently
|
||||
the graphics tests) will only run with a single copy.
|
||||
|
||||
Since the tests are based on constant time (variable work), a "system"
|
||||
run usually takes about 29 minutes; the "graphics" part about 18 minutes.
|
||||
A "gindex" run on a dual-core machine will do 2 "system" passes (single-
|
||||
and dual-processing) and one "graphics" run, for a total around one and
|
||||
a quarter hours.
|
||||
|
||||
============================================================================
|
||||
|
||||
Detailed Usage
|
||||
==============
|
||||
|
||||
The Run script takes a number of options which you can use to customise a
|
||||
test, and you can specify the names of the tests to run. The full usage
|
||||
is:
|
||||
|
||||
Run [ -q | -v ] [-i <n> ] [-c <n> [-c <n> ...]] [test ...]
|
||||
|
||||
The option flags are:
|
||||
|
||||
-q Run in quiet mode.
|
||||
-v Run in verbose mode.
|
||||
-i <count> Run <count> iterations for each test -- slower tests
|
||||
use <count> / 3, but at least 1. Defaults to 10 (3 for
|
||||
slow tests).
|
||||
-c <n> Run <n> copies of each test in parallel.
|
||||
|
||||
The -c option can be given multiple times; for example:
|
||||
|
||||
./Run -c 1 -c 4
|
||||
|
||||
will run a single-streamed pass, then a 4-streamed pass. Note that some
|
||||
tests (currently the graphics tests) will only run in a single-streamed pass.
|
||||
|
||||
The remaining non-flag arguments are taken to be the names of tests to run.
|
||||
The default is to run "index". See "Tests" below.
|
||||
|
||||
When running the tests, I do *not* recommend switching to single-user mode
|
||||
("init 1"). This seems to change the results in ways I don't understand,
|
||||
and it's not realistic (unless your system will actually be running in this
|
||||
mode, of course). However, if using a windowing system, you may want to
|
||||
switch to a minimal window setup (for example, log in to a "twm" session),
|
||||
so that randomly-churning background processes don't randomise the results
|
||||
too much. This is particularly true for the graphics tests.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
The available tests are organised into categories; when generating index
|
||||
scores (see "The BYTE Index" below) the results for each category are
|
||||
produced separately. The categories are:
|
||||
|
||||
system The original Unix system tests (not all are actually
|
||||
in the index)
|
||||
2d 2D graphics tests (not all are actually in the index)
|
||||
3d 3D graphics tests
|
||||
misc Various non-indexed tests
|
||||
|
||||
The following individual tests are available:
|
||||
|
||||
system:
|
||||
dhry2reg Dhrystone 2 using register variables
|
||||
whetstone-double Double-Precision Whetstone
|
||||
syscall System Call Overhead
|
||||
pipe Pipe Throughput
|
||||
context1 Pipe-based Context Switching
|
||||
spawn Process Creation
|
||||
execl Execl Throughput
|
||||
fstime-w File Write 1024 bufsize 2000 maxblocks
|
||||
fstime-r File Read 1024 bufsize 2000 maxblocks
|
||||
fstime File Copy 1024 bufsize 2000 maxblocks
|
||||
fsbuffer-w File Write 256 bufsize 500 maxblocks
|
||||
fsbuffer-r File Read 256 bufsize 500 maxblocks
|
||||
fsbuffer File Copy 256 bufsize 500 maxblocks
|
||||
fsdisk-w File Write 4096 bufsize 8000 maxblocks
|
||||
fsdisk-r File Read 4096 bufsize 8000 maxblocks
|
||||
fsdisk File Copy 4096 bufsize 8000 maxblocks
|
||||
shell1 Shell Scripts (1 concurrent) (runs "looper 60 multi.sh 1")
|
||||
shell8 Shell Scripts (8 concurrent) (runs "looper 60 multi.sh 8")
|
||||
shell16 Shell Scripts (8 concurrent) (runs "looper 60 multi.sh 16")
|
||||
|
||||
2d:
|
||||
2d-rects 2D graphics: rectangles
|
||||
2d-lines 2D graphics: lines
|
||||
2d-circle 2D graphics: circles
|
||||
2d-ellipse 2D graphics: ellipses
|
||||
2d-shapes 2D graphics: polygons
|
||||
2d-aashapes 2D graphics: aa polygons
|
||||
2d-polys 2D graphics: complex polygons
|
||||
2d-text 2D graphics: text
|
||||
2d-blit 2D graphics: images and blits
|
||||
2d-window 2D graphics: windows
|
||||
|
||||
3d:
|
||||
ubgears 3D graphics: gears
|
||||
|
||||
misc:
|
||||
C C Compiler Throughput ("looper 60 $cCompiler cctest.c")
|
||||
arithoh Arithoh (huh?)
|
||||
short Arithmetic Test (short) (this is arith.c configured for
|
||||
"short" variables; ditto for the ones below)
|
||||
int Arithmetic Test (int)
|
||||
long Arithmetic Test (long)
|
||||
float Arithmetic Test (float)
|
||||
double Arithmetic Test (double)
|
||||
dc Dc: sqrt(2) to 99 decimal places (runs
|
||||
"looper 30 dc < dc.dat", using your system's copy of "dc")
|
||||
hanoi Recursion Test -- Tower of Hanoi
|
||||
grep Grep for a string in a large file, using your system's
|
||||
copy of "grep"
|
||||
sysexec Exercise fork() and exec().
|
||||
|
||||
The following pseudo-test names are aliases for combinations of other
|
||||
tests:
|
||||
|
||||
arithmetic Runs arithoh, short, int, long, float, double,
|
||||
and whetstone-double
|
||||
dhry Alias for dhry2reg
|
||||
dhrystone Alias for dhry2reg
|
||||
whets Alias for whetstone-double
|
||||
whetstone Alias for whetstone-double
|
||||
load Runs shell1, shell8, and shell16
|
||||
misc Runs C, dc, and hanoi
|
||||
speed Runs the arithmetic and system groups
|
||||
oldsystem Runs execl, fstime, fsbuffer, fsdisk, pipe, context1,
|
||||
spawn, and syscall
|
||||
system Runs oldsystem plus shell1, shell8, and shell16
|
||||
fs Runs fstime-w, fstime-r, fstime, fsbuffer-w,
|
||||
fsbuffer-r, fsbuffer, fsdisk-w, fsdisk-r, and fsdisk
|
||||
shell Runs shell1, shell8, and shell16
|
||||
|
||||
index Runs the tests which constitute the official index:
|
||||
the oldsystem group, plus dhry2reg, whetstone-double,
|
||||
shell1, and shell8
|
||||
See "The BYTE Index" below for more information.
|
||||
graphics Runs the tests which constitute the graphics index:
|
||||
2d-rects, 2d-ellipse, 2d-aashapes, 2d-text, 2d-blit,
|
||||
2d-window, and ubgears
|
||||
gindex Runs the index and graphics groups, to generate both
|
||||
sets of index results
|
||||
|
||||
all Runs all tests
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
The BYTE Index
|
||||
==============
|
||||
|
||||
The purpose of this test is to provide a basic indicator of the performance
|
||||
of a Unix-like system; hence, multiple tests are used to test various
|
||||
aspects of the system's performance. These test results are then compared
|
||||
to the scores from a baseline system to produce an index value, which is
|
||||
generally easier to handle than the raw sores. The entire set of index
|
||||
values is then combined to make an overall index for the system.
|
||||
|
||||
Since 1995, the baseline system has been "George", a SPARCstation 20-61
|
||||
with 128 MB RAM, a SPARC Storage Array, and Solaris 2.3, whose ratings
|
||||
were set at 10.0. (So a system which scores 520 is 52 times faster than
|
||||
this machine.) Since the numbers are really only useful in a relative
|
||||
sense, there's no particular reason to update the base system, so for the
|
||||
sake of consistency it's probably best to leave it alone. George's scores
|
||||
are in the file "pgms/index.base"; this file is used to calculate the
|
||||
index scores for any particular run.
|
||||
|
||||
Over the years, various changes have been made to the set of tests in the
|
||||
index. Although there is a desire for a consistent baseline, various tests
|
||||
have been determined to be misleading, and have been removed; and a few
|
||||
alternatives have been added. These changes are detailed in the README,
|
||||
and should be born in mind when looking at old scores.
|
||||
|
||||
A number of tests are included in the benchmark suite which are not part of
|
||||
the index, for various reasons; these tests can of course be run manually.
|
||||
See "Tests" above.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Graphics Tests
|
||||
==============
|
||||
|
||||
As of version 5.1, UnixBench now contains some graphics benchmarks. These
|
||||
are intended to give a rough idea of the general graphics performance of
|
||||
a system.
|
||||
|
||||
The graphics tests are in categories "2d" and "3d", so the index scores
|
||||
for these tests are separate from the basic system index. This seems
|
||||
like a sensible division, since the graphics performance of a system
|
||||
depends largely on the graphics adaptor.
|
||||
|
||||
The tests currently consist of some 2D "x11perf" tests and "ubgears".
|
||||
|
||||
* The 2D tests are a selection of the x11perf tests, using the host
|
||||
system's x11perf command (which must be installed and in the search
|
||||
path). Only a few of the x11perf tests are used, in the interests
|
||||
of completing a test run in a reasonable time; if you want to do
|
||||
detailed diagnosis of an X server or graphics chip, then use x11perf
|
||||
directly.
|
||||
|
||||
* The 3D test is "ubgears", a modified version of the familiar "glxgears".
|
||||
This version runs for 5 seconds to "warm up", then performs a timed
|
||||
run and displays the average frames-per-second.
|
||||
|
||||
On multi-CPU systems, the graphics tests will only run in single-processing
|
||||
mode. This is because the meaning of running two copies of a test at once
|
||||
is dubious; and the test windows tend to overlay each other, meaning that
|
||||
the window behind isn't actually doing any work.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Multiple CPUs
|
||||
=============
|
||||
|
||||
If your system has multiple CPUs, the default behaviour is to run the selected
|
||||
tests twice -- once with one copy of each test program running at a time,
|
||||
and once with N copies, where N is the number of CPUs. (You can override
|
||||
this with the "-c" option; see "Detailed Usage" above.) This is designed to
|
||||
allow you to assess:
|
||||
|
||||
- the performance of your system when running a single task
|
||||
- the performance of your system when running multiple tasks
|
||||
- the gain from your system's implementation of parallel processing
|
||||
|
||||
The results, however, need to be handled with care. Here are the results
|
||||
of two runs on a dual-processor system, one in single-processing mode, one
|
||||
dual-processing:
|
||||
|
||||
Test Single Dual Gain
|
||||
-------------------- ------ ------ ----
|
||||
Dhrystone 2 562.5 1110.3 97%
|
||||
Double Whetstone 320.0 640.4 100%
|
||||
Execl Throughput 450.4 880.3 95%
|
||||
File Copy 1024 759.4 595.9 -22%
|
||||
File Copy 256 535.8 438.8 -18%
|
||||
File Copy 4096 1261.8 1043.4 -17%
|
||||
Pipe Throughput 481.0 979.3 104%
|
||||
Pipe-based Switching 326.8 1229.0 276%
|
||||
Process Creation 917.2 1714.1 87%
|
||||
Shell Scripts (1) 1064.9 1566.3 47%
|
||||
Shell Scripts (8) 1567.7 1709.9 9%
|
||||
System Call Overhead 944.2 1445.5 53%
|
||||
-------------------- ------ ------ ----
|
||||
Index Score: 678.2 1026.2 51%
|
||||
|
||||
As expected, the heavily CPU-dependent tasks -- dhrystone, whetstone,
|
||||
execl, pipe throughput, process creation -- show close to 100% gain when
|
||||
running 2 copies in parallel.
|
||||
|
||||
The Pipe-based Context Switching test measures context switching overhead
|
||||
by sending messages back and forth between 2 processes. I don't know why
|
||||
it shows such a huge gain with 2 copies (ie. 4 processes total) running,
|
||||
but it seems to be consistent on my system. I think this may be an issue
|
||||
with the SMP implementation.
|
||||
|
||||
The System Call Overhead shows a lesser gain, presumably because it uses a
|
||||
lot of CPU time in single-threaded kernel code. The shell scripts test with
|
||||
8 concurrent processes shows no gain -- because the test itself runs 8
|
||||
scripts in parallel, it's already using both CPUs, even when the benchmark
|
||||
is run in single-stream mode. The same test with one process per copy
|
||||
shows a real gain.
|
||||
|
||||
The filesystem throughput tests show a loss, instead of a gain, when
|
||||
multi-processing. That there's no gain is to be expected, since the tests
|
||||
are presumably constrained by the throughput of the I/O subsystem and the
|
||||
disk drive itself; the drop in performance is presumably down to the
|
||||
increased contention for resources, and perhaps greater disk head movement.
|
||||
|
||||
So what tests should you use, how many copies should you run, and how should
|
||||
you interpret the results? Well, that's up to you, since it depends on
|
||||
what it is you're trying to measure.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
The multi-processing mode is implemented at the level of test iterations.
|
||||
During each iteration of a test, N slave processes are started using fork().
|
||||
Each of these slaves executes the test program using fork() and exec(),
|
||||
reads and stores the entire output, times the run, and prints all the
|
||||
results to a pipe. The Run script reads the pipes for each of the slaves
|
||||
in turn to get the results and times. The scores are added, and the times
|
||||
averaged.
|
||||
|
||||
The result is that each test program has N copies running at once. They
|
||||
should all finish at around the same time, since they run for constant time.
|
||||
|
||||
If a test program itself starts off K multiple processes (as with the shell8
|
||||
test), then the effect will be that there are N * K processes running at
|
||||
once. This is probably not very useful for testing multi-CPU performance.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
The Language Setting
|
||||
====================
|
||||
|
||||
The $LANG environment variable determines how programs abnd library
|
||||
routines interpret text. This can have a big impact on the test results.
|
||||
|
||||
If $LANG is set to POSIX, or is left unset, text is treated as ASCII; if
|
||||
it is set to en_US.UTF-8, foir example, then text is treated as being
|
||||
encoded in UTF-8, which is more complex and therefore slower. Setting
|
||||
it to other languages can have varying results.
|
||||
|
||||
To ensure consistency between test runs, the Run script now (as of version
|
||||
5.1.1) sets $LANG to "en_US.utf8".
|
||||
|
||||
This setting which is configured with the variable "$language". You
|
||||
should not change this if you want to share your results to allow
|
||||
comparisons between systems; however, you may want to change it to see
|
||||
how different language settings affect performance.
|
||||
|
||||
Each test report now includes the language settings in use. The reported
|
||||
language is what is set in $LANG, and is not necessarily supported by the
|
||||
system; but we also report the character mapping and collation order which
|
||||
are actually in use (as reported by "locale").
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Interpreting the Results
|
||||
========================
|
||||
|
||||
Interpreting the results of these tests is tricky, and totally depends on
|
||||
what you're trying to measure.
|
||||
|
||||
For example, are you trying to measure how fast your CPU is? Or how good
|
||||
your compiler is? Because these tests are all recompiled using your host
|
||||
system's compiler, the performance of the compiler will inevitably impact
|
||||
the performance of the tests. Is this a problem? If you're choosing a
|
||||
system, you probably care about its overall speed, which may well depend
|
||||
on how good its compiler is; so including that in the test results may be
|
||||
the right answer. But you may want to ensure that the right compiler is
|
||||
used to build the tests.
|
||||
|
||||
On the other hand, with the vast majority of Unix systems being x86 / PC
|
||||
compatibles, running Linux and the GNU C compiler, the results will tend
|
||||
to be more dependent on the hardware; but the versions of the compiler and
|
||||
OS can make a big difference. (I measured a 50% gain between SUSE 10.1
|
||||
and OpenSUSE 10.2 on the same machine.) So you may want to make sure that
|
||||
all your test systems are running the same version of the OS; or at least
|
||||
publish the OS and compuiler versions with your results. Then again, it may
|
||||
be compiler performance that you're interested in.
|
||||
|
||||
The C test is very dubious -- it tests the speed of compilation. If you're
|
||||
running the exact same compiler on each system, OK; but otherwise, the
|
||||
results should probably be discarded. A slower compilation doesn't say
|
||||
anything about the speed of your system, since the compiler may simply be
|
||||
spending more time to super-optimise the code, which would actually make it
|
||||
faster.
|
||||
|
||||
This will be particularly true on architectures like IA-64 (Itanium etc.)
|
||||
where the compiler spends huge amounts of effort scheduling instructions
|
||||
to run in parallel, with a resultant significant gain in execution speed.
|
||||
|
||||
Some tests are even more dubious in terms of host-dependency -- for example,
|
||||
the "dc" test uses the host's version of dc (a calculator program). The
|
||||
version of this which is available can make a huge difference to the score,
|
||||
which is why it's not in the index group. Read through the release notes
|
||||
for more on these kinds of issues.
|
||||
|
||||
Another age-old issue is that of the benchmarks being too trivial to be
|
||||
meaningful. With compilers getting ever smarter, and performing more
|
||||
wide-ranging flow path analyses, the danger of parts of the benchmarks
|
||||
simply being optimised out of existance is always present.
|
||||
|
||||
All in all, the "index" and "gindex" tests (see above) are designed to
|
||||
give a reasonable measure of overall system performance; but the results
|
||||
of any test run should always be used with care.
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
Writing a Test
|
||||
==============
|
||||
|
||||
Writing a test program is pretty easy. Basically, a test is configured via
|
||||
a monster array in the Run script, which specifics (among other things) the
|
||||
program to execute and the parameters to pass it.
|
||||
|
||||
The test itself is simply a program which is given the optional parameters
|
||||
on the command line, and produces logging data on stdout and its results on
|
||||
stderr.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Test Configuration
|
||||
==================
|
||||
|
||||
In Run, all tests are named in the "$testList" array. This names the
|
||||
individual tests, and also sets up aliases for groups of tests, eg. "index".
|
||||
|
||||
The test specifications are in the "$testParams" array. This contains the
|
||||
details of each individual test as a hash. The fields in the hash are:
|
||||
|
||||
* "logmsg": the full name to display for this test.
|
||||
* "cat": the category this test belongs to; must be configured
|
||||
in $testCats.
|
||||
* "prog": the name of the program to execute; defaults to the name of
|
||||
the benchmark.
|
||||
* "repeat": number of passes to run; either 'short' (the default),
|
||||
'long', or 'single'. For 'short' and 'long', the actual numbers of
|
||||
passes are given by $shortIterCount and $longIterCount, which are
|
||||
configured at the top of the script or by the "-i" flag. 'single'
|
||||
means just run one pass; this should be used for test which do their
|
||||
own multi-pass handling internally.
|
||||
* "stdout": non-0 to add the test's stdout to the log file; defaults to 1.
|
||||
Set to 0 for tests that are too wordy.
|
||||
* "stdin": name of a file to send to the program's stdin; default null.
|
||||
* "options": options to be put on the program's command line; default null.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Output Format
|
||||
=============
|
||||
|
||||
The results on stderr take the form of a line header and fields, separated
|
||||
by "|" characters. A result line can be one of:
|
||||
|
||||
COUNT|score|timebase|label
|
||||
TIME|seconds
|
||||
ERROR|message
|
||||
|
||||
Any other text on stderr is treated as if it were:
|
||||
|
||||
ERROR|text
|
||||
|
||||
Any output to stdout is placed in a log file, and can be used for debugging.
|
||||
|
||||
COUNT
|
||||
-----
|
||||
|
||||
The COUNT line is the line used to report a test score.
|
||||
|
||||
* "score" is the result, typically the number of loops performed during
|
||||
the run
|
||||
* "timebase" is the time base used for the final report to the user. A
|
||||
value of 1 reports the score as is; a value of 60, for example, divides
|
||||
the time taken by 60 to get loops per minute. Atimebase of zero indicates
|
||||
that the score is already a rate, ie. a count of things per second.
|
||||
* "label" is the label to use for the score; like "lps" (loops per
|
||||
second), etc.
|
||||
|
||||
TIME
|
||||
----
|
||||
|
||||
The TIME line is optionally used to report the time taken. The Run script
|
||||
normally measures this, but if your test has signifant overhead outside the
|
||||
actual test loop, you should use TIME to report the time taken for the actual
|
||||
test. The argument is the time in seconds in floating-point.
|
||||
|
||||
ERROR
|
||||
-----
|
||||
|
||||
The argument is an error message; this will abort the benchmarking run and
|
||||
display the message.
|
||||
|
||||
Any output to stderr which is not a formatted line will be treated as an
|
||||
error message, so use of ERROR is optional.
|
||||
|
||||
|
||||
============================================================================
|
||||
|
||||
Test Examples
|
||||
=============
|
||||
|
||||
Iteration Count
|
||||
---------------
|
||||
|
||||
The simplest thing is to count the number of loops executed in a given time;
|
||||
see eg. arith.c. The utlilty functions in timeit.c can be used to implement
|
||||
the fixed time interval, which is generally passed in on the command line.
|
||||
|
||||
The result is reported simply as the number of iterations completed:
|
||||
|
||||
fprintf(stderr,"COUNT|%lu|1|lps\n", iterations);
|
||||
|
||||
The bnenchmark framework will measure the time taken itself. If the test
|
||||
code has significant overhead (eg. a "pump-priming" pass), then you should
|
||||
explicitly report the time taken for the test by adding a line like this:
|
||||
|
||||
fprintf(stderr, "TIME|%.1f\n", seconds);
|
||||
|
||||
If you want results reported as loops per minute, then set timebase to 60:
|
||||
|
||||
fprintf(stderr,"COUNT|%lu|60|lpm\n", iterations);
|
||||
|
||||
Note that this only affects the final report; all times passed to or
|
||||
from the test are still in seconds.
|
||||
|
||||
Rate
|
||||
----
|
||||
|
||||
The other technique is to calculate the rate (things per second) in the test,
|
||||
and report that directly. To do this, just set timebase to 0:
|
||||
|
||||
fprintf(stderr, "COUNT|%ld|0|KBps\n", kbytes_per_sec);
|
||||
|
||||
Again, you can use TIME to explicitly report the time taken:
|
||||
|
||||
fprintf(stderr, "TIME|%.1f\n", end - start);
|
||||
|
||||
but this isn't so important since you've already calculated the rate.
|
||||
|
||||
@@ -1,476 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
|
||||
|
||||
############################################################################
|
||||
# gfx-x11: a front-end for x11perf. Runs a selected x11perf test, and
|
||||
# produces output in the format needed by UnixBench.
|
||||
############################################################################
|
||||
# Modification Log:
|
||||
# 2007.09.26 Ian Smith Created
|
||||
############################################################################
|
||||
|
||||
# This program runs sets of x11perf tests, indexes the results against
|
||||
# a common base reference system (see $testData below), and reports the
|
||||
# final score.
|
||||
#
|
||||
# Usage:
|
||||
# gfx-x11 <group> <reps> <time>
|
||||
# where:
|
||||
# <group> is one of the test groups defined in $testGroups below
|
||||
# <reps> is the number of repeats to do per test (the -repeat
|
||||
# argument to x11perf)
|
||||
# <time> is the number of seconds to run each repeat for (the
|
||||
# -time argument to x11perf)
|
||||
# Note that x11perf runs a calibration pass before the requested number
|
||||
# of test passes. The score we compute for a test is the average of the
|
||||
# test passes, divided by the base value in $testData, times 1000.0.
|
||||
# The final score we report is the average of the test scores.
|
||||
|
||||
|
||||
############################################################################
|
||||
# TEST DATA
|
||||
############################################################################
|
||||
|
||||
# This array lists all of the x11perf tests, together with their scores
|
||||
# on an HP Compaq nc8430, with an ATI Mobility Radeon X1600 (256MB)
|
||||
# graphics adapter. There isn't anything special about this reference
|
||||
# system, but scaling all the scores back to a single reference system
|
||||
# allows us to average them in a roughly meaningful way, which in turn
|
||||
# allows us to produce sensible scores for the test groups defined below.
|
||||
#
|
||||
# The results we report are indexed to these values, at a base of 1000.0.
|
||||
my $testData = {
|
||||
'dot' => [ 31700000.0, "Dot" ],
|
||||
'rect1' => [ 18400000.0, "1x1 rectangle" ],
|
||||
'rect10' => [ 7180000.0, "10x10 rectangle" ],
|
||||
'rect100' => [ 110000.0, "100x100 rectangle" ],
|
||||
'rect500' => [ 4110.0, "500x500 rectangle" ],
|
||||
'srect1' => [ 15800000.0, "1x1 stippled rectangle (8x8 stipple)" ],
|
||||
'srect10' => [ 7400000.0, "10x10 stippled rectangle (8x8 stipple)" ],
|
||||
'srect100' => [ 110000.0, "100x100 stippled rectangle (8x8 stipple)" ],
|
||||
'srect500' => [ 4110.0, "500x500 stippled rectangle (8x8 stipple)" ],
|
||||
'osrect1' => [ 15900000.0, "1x1 opaque stippled rectangle (8x8 stipple)" ],
|
||||
'osrect10' => [ 7170000.0, "10x10 opaque stippled rectangle (8x8 stipple)" ],
|
||||
'osrect100' => [ 110000.0, "100x100 opaque stippled rectangle (8x8 stipple)" ],
|
||||
'osrect500' => [ 4110.0, "500x500 opaque stippled rectangle (8x8 stipple)" ],
|
||||
'tilerect1' => [ 15800000.0, "1x1 tiled rectangle (4x4 tile)" ],
|
||||
'tilerect10' => [ 7170000.0, "10x10 tiled rectangle (4x4 tile)" ],
|
||||
'tilerect100' => [ 110000.0, "100x100 tiled rectangle (4x4 tile)" ],
|
||||
'tilerect500' => [ 4110.0, "500x500 tiled rectangle (4x4 tile)" ],
|
||||
'oddsrect1' => [ 2990000.0, "1x1 stippled rectangle (17x15 stipple)" ],
|
||||
'oddsrect10' => [ 1490000.0, "10x10 stippled rectangle (17x15 stipple)" ],
|
||||
'oddsrect100' => [ 55600.0, "100x100 stippled rectangle (17x15 stipple)" ],
|
||||
'oddsrect500' => [ 2360.0, "500x500 stippled rectangle (17x15 stipple)" ],
|
||||
'oddosrect1' => [ 2990000.0, "1x1 opaque stippled rectangle (17x15 stipple)" ],
|
||||
'oddosrect10' => [ 1430000.0, "10x10 opaque stippled rectangle (17x15 stipple)" ],
|
||||
'oddosrect100' => [ 54500.0, "100x100 opaque stippled rectangle (17x15 stipple)" ],
|
||||
'oddosrect500' => [ 2320.0, "500x500 opaque stippled rectangle (17x15 stipple)" ],
|
||||
'oddtilerect1' => [ 2990000.0, "1x1 tiled rectangle (17x15 tile)" ],
|
||||
'oddtilerect10' => [ 1430000.0, "10x10 tiled rectangle (17x15 tile)" ],
|
||||
'oddtilerect100' => [ 54500.0, "100x100 tiled rectangle (17x15 tile)" ],
|
||||
'oddtilerect500' => [ 2320.0, "500x500 tiled rectangle (17x15 tile)" ],
|
||||
'bigsrect1' => [ 4300000.0, "1x1 stippled rectangle (161x145 stipple)" ],
|
||||
'bigsrect10' => [ 705000.0, "10x10 stippled rectangle (161x145 stipple)" ],
|
||||
'bigsrect100' => [ 12300.0, "100x100 stippled rectangle (161x145 stipple)" ],
|
||||
'bigsrect500' => [ 524.0, "500x500 stippled rectangle (161x145 stipple)" ],
|
||||
'bigosrect1' => [ 3980000.0, "1x1 opaque stippled rectangle (161x145 stipple)" ],
|
||||
'bigosrect10' => [ 644000.0, "10x10 opaque stippled rectangle (161x145 stipple)" ],
|
||||
'bigosrect100' => [ 12800.0, "100x100 opaque stippled rectangle (161x145 stipple)" ],
|
||||
'bigosrect500' => [ 584.0, "500x500 opaque stippled rectangle (161x145 stipple)" ],
|
||||
'bigtilerect1' => [ 5970000.0, "1x1 tiled rectangle (161x145 tile)" ],
|
||||
'bigtilerect10' => [ 684000.0, "10x10 tiled rectangle (161x145 tile)" ],
|
||||
'bigtilerect100' => [ 16200.0, "100x100 tiled rectangle (161x145 tile)" ],
|
||||
'bigtilerect500' => [ 872.0, "500x500 tiled rectangle (161x145 tile)" ],
|
||||
'eschertilerect1' => [ 5940000.0, "1x1 tiled rectangle (216x208 tile)" ],
|
||||
'eschertilerect10' => [ 639000.0, "10x10 tiled rectangle (216x208 tile)" ],
|
||||
'eschertilerect100' => [ 18000.0, "100x100 tiled rectangle (216x208 tile)" ],
|
||||
'eschertilerect500' => [ 922.0, "500x500 tiled rectangle (216x208 tile)" ],
|
||||
'seg1' => [ 28800000.0, "1-pixel line segment" ],
|
||||
'seg10' => [ 4460000.0, "10-pixel line segment" ],
|
||||
'seg100' => [ 470000.0, "100-pixel line segment" ],
|
||||
'seg500' => [ 94600.0, "500-pixel line segment" ],
|
||||
'seg100c1' => [ 449000.0, "100-pixel line segment (1 kid)" ],
|
||||
'seg100c2' => [ 432000.0, "100-pixel line segment (2 kids)" ],
|
||||
'seg100c3' => [ 421000.0, "100-pixel line segment (3 kids)" ],
|
||||
'dseg10' => [ 3720000.0, "10-pixel dashed segment" ],
|
||||
'dseg100' => [ 687000.0, "100-pixel dashed segment" ],
|
||||
'ddseg100' => [ 454000.0, "100-pixel double-dashed segment" ],
|
||||
'hseg10' => [ 7020000.0, "10-pixel horizontal line segment" ],
|
||||
'hseg100' => [ 2170000.0, "100-pixel horizontal line segment" ],
|
||||
'hseg500' => [ 456000.0, "500-pixel horizontal line segment" ],
|
||||
'vseg10' => [ 3990000.0, "10-pixel vertical line segment" ],
|
||||
'vseg100' => [ 411000.0, "100-pixel vertical line segment" ],
|
||||
'vseg500' => [ 82400.0, "500-pixel vertical line segment" ],
|
||||
'whseg10' => [ 2880000.0, "10x1 wide horizontal line segment" ],
|
||||
'whseg100' => [ 616000.0, "100x10 wide horizontal line segment" ],
|
||||
'whseg500' => [ 33300.0, "500x50 wide horizontal line segment" ],
|
||||
'wvseg10' => [ 2890000.0, "10x1 wide vertical line segment" ],
|
||||
'wvseg100' => [ 584000.0, "100x10 wide vertical line segment" ],
|
||||
'wvseg500' => [ 31700.0, "500x50 wide vertical line segment" ],
|
||||
'line1' => [ 28300000.0, "1-pixel line" ],
|
||||
'line10' => [ 4470000.0, "10-pixel line" ],
|
||||
'line100' => [ 472000.0, "100-pixel line" ],
|
||||
'line500' => [ 94200.0, "500-pixel line" ],
|
||||
'dline10' => [ 3640000.0, "10-pixel dashed line" ],
|
||||
'dline100' => [ 673000.0, "100-pixel dashed line" ],
|
||||
'ddline100' => [ 453000.0, "100-pixel double-dashed line" ],
|
||||
'wline10' => [ 908000.0, "10x1 wide line" ],
|
||||
'wline100' => [ 146000.0, "100x10 wide line" ],
|
||||
'wline500' => [ 30600.0, "500x50 wide line" ],
|
||||
'wdline100' => [ 69900.0, "100x10 wide dashed line" ],
|
||||
'wddline100' => [ 60600.0, "100x10 wide double-dashed line" ],
|
||||
'orect10' => [ 5100000.0, "10x10 rectangle outline" ],
|
||||
'orect100' => [ 709000.0, "100x100 rectangle outline" ],
|
||||
'orect500' => [ 146000.0, "500x500 rectangle outline" ],
|
||||
'worect10' => [ 4530000.0, "10x10 wide rectangle outline" ],
|
||||
'worect100' => [ 204000.0, "100x100 wide rectangle outline" ],
|
||||
'worect500' => [ 9790.0, "500x500 wide rectangle outline" ],
|
||||
'circle1' => [ 5160000.0, "1-pixel circle" ],
|
||||
'circle10' => [ 1160000.0, "10-pixel circle" ],
|
||||
'circle100' => [ 141000.0, "100-pixel circle" ],
|
||||
'circle500' => [ 28900.0, "500-pixel circle" ],
|
||||
'dcircle100' => [ 98400.0, "100-pixel dashed circle" ],
|
||||
'ddcircle100' => [ 75000.0, "100-pixel double-dashed circle" ],
|
||||
'wcircle10' => [ 780000.0, "10-pixel wide circle" ],
|
||||
'wcircle100' => [ 90900.0, "100-pixel wide circle" ],
|
||||
'wcircle500' => [ 11300.0, "500-pixel wide circle" ],
|
||||
'wdcircle100' => [ 8100.0, "100-pixel wide dashed circle" ],
|
||||
'wddcircle100' => [ 8300.0, "100-pixel wide double-dashed circle" ],
|
||||
'pcircle10' => [ 1270000.0, "10-pixel partial circle" ],
|
||||
'pcircle100' => [ 212000.0, "100-pixel partial circle" ],
|
||||
'wpcircle10' => [ 104000.0, "10-pixel wide partial circle" ],
|
||||
'wpcircle100' => [ 39000.0, "100-pixel wide partial circle" ],
|
||||
'fcircle1' => [ 61300000.0, "1-pixel solid circle" ],
|
||||
'fcircle10' => [ 1720000.0, "10-pixel solid circle" ],
|
||||
'fcircle100' => [ 120000.0, "100-pixel solid circle" ],
|
||||
'fcircle500' => [ 5170.0, "500-pixel solid circle" ],
|
||||
'fcpcircle10' => [ 981000.0, "10-pixel fill chord partial circle" ],
|
||||
'fcpcircle100' => [ 205000.0, "100-pixel fill chord partial circle" ],
|
||||
'fspcircle10' => [ 876000.0, "10-pixel fill slice partial circle" ],
|
||||
'fspcircle100' => [ 187000.0, "100-pixel fill slice partial circle" ],
|
||||
'ellipse10' => [ 1410000.0, "10-pixel ellipse" ],
|
||||
'ellipse100' => [ 172000.0, "100-pixel ellipse" ],
|
||||
'ellipse500' => [ 35100.0, "500-pixel ellipse" ],
|
||||
'dellipse100' => [ 114000.0, "100-pixel dashed ellipse" ],
|
||||
'ddellipse100' => [ 88900.0, "100-pixel double-dashed ellipse" ],
|
||||
'wellipse10' => [ 889000.0, "10-pixel wide ellipse" ],
|
||||
'wellipse100' => [ 124000.0, "100-pixel wide ellipse" ],
|
||||
'wellipse500' => [ 15600.0, "500-pixel wide ellipse" ],
|
||||
'wdellipse100' => [ 7730.0, "100-pixel wide dashed ellipse" ],
|
||||
'wddellipse100' => [ 6680.0, "100-pixel wide double-dashed ellipse" ],
|
||||
'pellipse10' => [ 1350000.0, "10-pixel partial ellipse" ],
|
||||
'pellipse100' => [ 260000.0, "100-pixel partial ellipse" ],
|
||||
'wpellipse10' => [ 97900.0, "10-pixel wide partial ellipse" ],
|
||||
'wpellipse100' => [ 16800.0, "100-pixel wide partial ellipse" ],
|
||||
'fellipse10' => [ 2110000.0, "10-pixel filled ellipse" ],
|
||||
'fellipse100' => [ 212000.0, "100-pixel filled ellipse" ],
|
||||
'fellipse500' => [ 11000.0, "500-pixel filled ellipse" ],
|
||||
'fcpellipse10' => [ 1060000.0, "10-pixel fill chord partial ellipse" ],
|
||||
'fcpellipse100' => [ 296000.0, "100-pixel fill chord partial ellipse" ],
|
||||
'fspellipse10' => [ 945000.0, "10-pixel fill slice partial ellipse" ],
|
||||
'fspellipse100' => [ 269000.0, "100-pixel fill slice partial ellipse" ],
|
||||
'triangle1' => [ 2460000.0, "Fill 1x1 equivalent triangle" ],
|
||||
'triangle10' => [ 969000.0, "Fill 10x10 equivalent triangle" ],
|
||||
'triangle100' => [ 97000.0, "Fill 100x100 equivalent triangle" ],
|
||||
'trap1' => [ 2630000.0, "Fill 1x1 trapezoid" ],
|
||||
'trap10' => [ 1260000.0, "Fill 10x10 trapezoid" ],
|
||||
'trap100' => [ 106000.0, "Fill 100x100 trapezoid" ],
|
||||
'trap300' => [ 11600.0, "Fill 300x300 trapezoid" ],
|
||||
'strap1' => [ 2010000.0, "Fill 1x1 stippled trapezoid (8x8 stipple)" ],
|
||||
'strap10' => [ 910000.0, "Fill 10x10 stippled trapezoid (8x8 stipple)" ],
|
||||
'strap100' => [ 104000.0, "Fill 100x100 stippled trapezoid (8x8 stipple)" ],
|
||||
'strap300' => [ 11700.0, "Fill 300x300 stippled trapezoid (8x8 stipple)" ],
|
||||
'ostrap1' => [ 2000000.0, "Fill 1x1 opaque stippled trapezoid (8x8 stipple)" ],
|
||||
'ostrap10' => [ 907000.0, "Fill 10x10 opaque stippled trapezoid (8x8 stipple)" ],
|
||||
'ostrap100' => [ 104000.0, "Fill 100x100 opaque stippled trapezoid (8x8 stipple)" ],
|
||||
'ostrap300' => [ 11600.0, "Fill 300x300 opaque stippled trapezoid (8x8 stipple)" ],
|
||||
'tiletrap1' => [ 1430000.0, "Fill 1x1 tiled trapezoid (4x4 tile)" ],
|
||||
'tiletrap10' => [ 778000.0, "Fill 10x10 tiled trapezoid (4x4 tile)" ],
|
||||
'tiletrap100' => [ 104000.0, "Fill 100x100 tiled trapezoid (4x4 tile)" ],
|
||||
'tiletrap300' => [ 11600.0, "Fill 300x300 tiled trapezoid (4x4 tile)" ],
|
||||
'oddstrap1' => [ 1700000.0, "Fill 1x1 stippled trapezoid (17x15 stipple)" ],
|
||||
'oddstrap10' => [ 296000.0, "Fill 10x10 stippled trapezoid (17x15 stipple)" ],
|
||||
'oddstrap100' => [ 18600.0, "Fill 100x100 stippled trapezoid (17x15 stipple)" ],
|
||||
'oddstrap300' => [ 2090.0, "Fill 300x300 stippled trapezoid (17x15 stipple)" ],
|
||||
'oddostrap1' => [ 1830000.0, "Fill 1x1 opaque stippled trapezoid (17x15 stipple)" ],
|
||||
'oddostrap10' => [ 296000.0, "Fill 10x10 opaque stippled trapezoid (17x15 stipple)" ],
|
||||
'oddostrap100' => [ 18400.0, "Fill 100x100 opaque stippled trapezoid (17x15 stipple)" ],
|
||||
'oddostrap300' => [ 2080.0, "Fill 300x300 opaque stippled trapezoid (17x15 stipple)" ],
|
||||
'oddtiletrap1' => [ 1710000.0, "Fill 1x1 tiled trapezoid (17x15 tile)" ],
|
||||
'oddtiletrap10' => [ 296000.0, "Fill 10x10 tiled trapezoid (17x15 tile)" ],
|
||||
'oddtiletrap100' => [ 18400.0, "Fill 100x100 tiled trapezoid (17x15 tile)" ],
|
||||
'oddtiletrap300' => [ 2080.0, "Fill 300x300 tiled trapezoid (17x15 tile)" ],
|
||||
'bigstrap1' => [ 1510000.0, "Fill 1x1 stippled trapezoid (161x145 stipple)" ],
|
||||
'bigstrap10' => [ 235000.0, "Fill 10x10 stippled trapezoid (161x145 stipple)" ],
|
||||
'bigstrap100' => [ 9110.0, "Fill 100x100 stippled trapezoid (161x145 stipple)" ],
|
||||
'bigstrap300' => [ 1260.0, "Fill 300x300 stippled trapezoid (161x145 stipple)" ],
|
||||
'bigostrap1' => [ 1480000.0, "Fill 1x1 opaque stippled trapezoid (161x145 stipple)" ],
|
||||
'bigostrap10' => [ 213000.0, "Fill 10x10 opaque stippled trapezoid (161x145 stipple)" ],
|
||||
'bigostrap100' => [ 8830.0, "Fill 100x100 opaque stippled trapezoid (161x145 stipple)" ],
|
||||
'bigostrap300' => [ 1420.0, "Fill 300x300 opaque stippled trapezoid (161x145 stipple)" ],
|
||||
'bigtiletrap1' => [ 1630000.0, "Fill 1x1 tiled trapezoid (161x145 tile)" ],
|
||||
'bigtiletrap10' => [ 272000.0, "Fill 10x10 tiled trapezoid (161x145 tile)" ],
|
||||
'bigtiletrap100' => [ 12900.0, "Fill 100x100 tiled trapezoid (161x145 tile)" ],
|
||||
'bigtiletrap300' => [ 2350.0, "Fill 300x300 tiled trapezoid (161x145 tile)" ],
|
||||
'eschertiletrap1' => [ 1650000.0, "Fill 1x1 tiled trapezoid (216x208 tile)" ],
|
||||
'eschertiletrap10' => [ 273000.0, "Fill 10x10 tiled trapezoid (216x208 tile)" ],
|
||||
'eschertiletrap100' => [ 13400.0, "Fill 100x100 tiled trapezoid (216x208 tile)" ],
|
||||
'eschertiletrap300' => [ 2450.0, "Fill 300x300 tiled trapezoid (216x208 tile)" ],
|
||||
'aatrap1' => [ 260000.0, "Fill 1x1 aa trap" ],
|
||||
'aatrap10' => [ 23500.0, "Fill 10x10 aa trap" ],
|
||||
'aatrap100' => [ 13300.0, "Fill 100x100 aa trap" ],
|
||||
'aatrap300' => [ 4450.0, "Fill 300x300 aa trap" ],
|
||||
'aa4trap1' => [ 2150.0, "Fill 1x1 aa trap with 4 bit alpha" ],
|
||||
'aa4trap10' => [ 2130.0, "Fill 10x10 aa trap with 4 bit alpha" ],
|
||||
'aa4trap100' => [ 1890.0, "Fill 100x100 aa trap with 4 bit alpha" ],
|
||||
'aa4trap300' => [ 1460.0, "Fill 300x300 aa trap with 4 bit alpha" ],
|
||||
'aa1trap1' => [ 2200000.0, "Fill 1x1 aa trap with 1 bit alpha" ],
|
||||
'aa1trap10' => [ 357000.0, "Fill 10x10 aa trap with 1 bit alpha" ],
|
||||
'aa1trap100' => [ 167000.0, "Fill 100x100 aa trap with 1 bit alpha" ],
|
||||
'aa1trap300' => [ 67000.0, "Fill 300x300 aa trap with 1 bit alpha" ],
|
||||
'aatrap2x1' => [ 368000.0, "Fill 2x1 aa trap" ],
|
||||
'aatrap2x10' => [ 25700.0, "Fill 2x10 aa trap" ],
|
||||
'aatrap2x100' => [ 12400.0, "Fill 2x100 aa trap" ],
|
||||
'aatrap2x300' => [ 5710.0, "Fill 2x300 aa trap" ],
|
||||
'aatrapezoid1' => [ 372000.0, "Fill 1x1 aa trapezoid" ],
|
||||
'aatrapezoid10' => [ 137000.0, "Fill 10x10 aa trapezoid" ],
|
||||
'aatrapezoid100' => [ 9590.0, "Fill 100x100 aa trapezoid" ],
|
||||
'aatrapezoid300' => [ 1420.0, "Fill 300x300 aa trapezoid" ],
|
||||
'addaatrapezoid1' => [ 433000.0, "Fill 1x1 aa pre-added trapezoid" ],
|
||||
'addaatrapezoid10' => [ 24100.0, "Fill 10x10 aa pre-added trapezoid" ],
|
||||
'addaatrapezoid100' => [ 13300.0, "Fill 100x100 aa pre-added trapezoid" ],
|
||||
'addaatrapezoid300' => [ 4460.0, "Fill 300x300 aa pre-added trapezoid" ],
|
||||
'complex10' => [ 655000.0, "Fill 10x10 equivalent complex polygon" ],
|
||||
'complex100' => [ 87000.0, "Fill 100x100 equivalent complex polygons" ],
|
||||
'64poly10convex' => [ 481000.0, "Fill 10x10 64-gon (Convex)" ],
|
||||
'64poly100convex' => [ 105000.0, "Fill 100x100 64-gon (Convex)" ],
|
||||
'64poly10complex' => [ 353000.0, "Fill 10x10 64-gon (Complex)" ],
|
||||
'64poly100complex' => [ 105000.0, "Fill 100x100 64-gon (Complex)" ],
|
||||
'ftext' => [ 2200000.0, "Char in 80-char line (6x13)" ],
|
||||
'f8text' => [ 1970000.0, "Char in 70-char line (8x13)" ],
|
||||
'f9text' => [ 1690000.0, "Char in 60-char line (9x15)" ],
|
||||
'f14text16' => [ 679000.0, "Char16 in 40-char line (k14)" ],
|
||||
'f24text16' => [ 272000.0, "Char16 in 23-char line (k24)" ],
|
||||
'tr10text' => [ 2520000.0, "Char in 80-char line (TR 10)" ],
|
||||
'tr24text' => [ 940000.0, "Char in 30-char line (TR 24)" ],
|
||||
'polytext' => [ 2230000.0, "Char in 20/40/20 line (6x13, TR 10)" ],
|
||||
'polytext16' => [ 369000.0, "Char16 in 7/14/7 line (k14, k24)" ],
|
||||
'fitext' => [ 1350000.0, "Char in 80-char image line (6x13)" ],
|
||||
'f8itext' => [ 1130000.0, "Char in 70-char image line (8x13)" ],
|
||||
'f9itext' => [ 902000.0, "Char in 60-char image line (9x15)" ],
|
||||
'f14itext16' => [ 449000.0, "Char16 in 40-char image line (k14)" ],
|
||||
'f24itext16' => [ 169000.0, "Char16 in 23-char image line (k24)" ],
|
||||
'tr10itext' => [ 1590000.0, "Char in 80-char image line (TR 10)" ],
|
||||
'tr24itext' => [ 435000.0, "Char in 30-char image line (TR 24)" ],
|
||||
'aa10text' => [ 53200.0, "Char in 80-char aa line (Charter 10)" ],
|
||||
'aa24text' => [ 13300.0, "Char in 30-char aa line (Charter 24)" ],
|
||||
'aaftext' => [ 45200.0, "Char in 80-char aa line (Courier 12)" ],
|
||||
'a10text' => [ 53100.0, "Char in 80-char a line (Charter 10)" ],
|
||||
'a24text' => [ 13300.0, "Char in 30-char a line (Charter 24)" ],
|
||||
'aftext' => [ 45200.0, "Char in 80-char a line (Courier 12)" ],
|
||||
'rgb10text' => [ 49400.0, "Char in 80-char rgb line (Charter 10)" ],
|
||||
'rgb24text' => [ 10200.0, "Char in 30-char rgb line (Charter 24)" ],
|
||||
'rgbftext' => [ 42200.0, "Char in 80-char rgb line (Courier 12)" ],
|
||||
'caa10text' => [ 15300.0, "Char in 80-char aa core line (Charter 10)" ],
|
||||
'caa24text' => [ 2540.0, "Char in 30-char aa core line (Charter 24)" ],
|
||||
'caaftext' => [ 10900.0, "Char in 80-char aa core line (Courier 12)" ],
|
||||
'ca10text' => [ 15300.0, "Char in 80-char a core line (Charter 10)" ],
|
||||
'ca24text' => [ 2540.0, "Char in 30-char a core line (Charter 24)" ],
|
||||
'caftext' => [ 10900.0, "Char in 80-char a core line (Courier 12)" ],
|
||||
'rgb10text' => [ 15000.0, "Char in 80-char rgb core line (Charter 10)" ],
|
||||
'rgb24text' => [ 2510.0, "Char in 30-char rgb core line (Charter 24)" ],
|
||||
'rgbftext' => [ 10700.0, "Char in 80-char rgb core line (Courier 12)" ],
|
||||
'scroll10' => [ 1310000.0, "Scroll 10x10 pixels" ],
|
||||
'scroll100' => [ 52000.0, "Scroll 100x100 pixels" ],
|
||||
'scroll500' => [ 2190.0, "Scroll 500x500 pixels" ],
|
||||
'copywinwin10' => [ 1030000.0, "Copy 10x10 from window to window" ],
|
||||
'copywinwin100' => [ 52200.0, "Copy 100x100 from window to window" ],
|
||||
'copywinwin500' => [ 2080.0, "Copy 500x500 from window to window" ],
|
||||
'copypixwin10' => [ 502000.0, "Copy 10x10 from pixmap to window" ],
|
||||
'copypixwin100' => [ 20300.0, "Copy 100x100 from pixmap to window" ],
|
||||
'copypixwin500' => [ 1020.0, "Copy 500x500 from pixmap to window" ],
|
||||
'copywinpix10' => [ 7730.0, "Copy 10x10 from window to pixmap" ],
|
||||
'copywinpix100' => [ 127.0, "Copy 100x100 from window to pixmap" ],
|
||||
'copywinpix500' => [ 5.0, "Copy 500x500 from window to pixmap" ],
|
||||
'copypixpix10' => [ 1260000.0, "Copy 10x10 from pixmap to pixmap" ],
|
||||
'copypixpix100' => [ 56300.0, "Copy 100x100 from pixmap to pixmap" ],
|
||||
'copypixpix500' => [ 2470.0, "Copy 500x500 from pixmap to pixmap" ],
|
||||
'copyplane10' => [ 466000.0, "Copy 10x10 1-bit deep plane" ],
|
||||
'copyplane100' => [ 13700.0, "Copy 100x100 1-bit deep plane" ],
|
||||
'copyplane500' => [ 671.0, "Copy 500x500 1-bit deep plane" ],
|
||||
'deepcopyplane10' => [ 151000.0, "Copy 10x10 n-bit deep plane" ],
|
||||
'deepcopyplane100' => [ 6090.0, "Copy 100x100 n-bit deep plane" ],
|
||||
'deepcopyplane500' => [ 278.0, "Copy 500x500 n-bit deep plane" ],
|
||||
'putimage10' => [ 434000.0, "PutImage 10x10 square" ],
|
||||
'putimage100' => [ 13600.0, "PutImage 100x100 square" ],
|
||||
'putimage500' => [ 713.0, "PutImage 500x500 square" ],
|
||||
'putimagexy10' => [ 321.0, "PutImage XY 10x10 square" ],
|
||||
'putimagexy100' => [ 3.2, "PutImage XY 100x100 square" ],
|
||||
'putimagexy500' => [ 0.1, "PutImage XY 500x500 square" ],
|
||||
'shmput10' => [ 465000.0, "ShmPutImage 10x10 square" ],
|
||||
'shmput100' => [ 20200.0, "ShmPutImage 100x100 square" ],
|
||||
'shmput500' => [ 1020.0, "ShmPutImage 500x500 square" ],
|
||||
'shmputxy10' => [ 31400.0, "ShmPutImage XY 10x10 square" ],
|
||||
'shmputxy100' => [ 458.0, "ShmPutImage XY 100x100 square" ],
|
||||
'shmputxy500' => [ 19.0, "ShmPutImage XY 500x500 square" ],
|
||||
'getimage10' => [ 6650.0, "GetImage 10x10 square" ],
|
||||
'getimage100' => [ 77.0, "GetImage 100x100 square" ],
|
||||
'getimage500' => [ 3.1, "GetImage 500x500 square" ],
|
||||
'getimagexy10' => [ 320.0, "GetImage XY 10x10 square" ],
|
||||
'getimagexy100' => [ 3.2, "GetImage XY 100x100 square" ],
|
||||
'getimagexy500' => [ 0.1, "GetImage XY 500x500 square" ],
|
||||
'noop' => [ 8760000.0, "X protocol NoOperation" ],
|
||||
'pointer' => [ 54800.0, "QueryPointer" ],
|
||||
'prop' => [ 50900.0, "GetProperty" ],
|
||||
'gc' => [ 1190000.0, "Change graphics context" ],
|
||||
'create' => [ 597000.0, "Create and map subwindows (25 kids)" ],
|
||||
'ucreate' => [ 1100000.0, "Create unmapped window (25 kids)" ],
|
||||
'map' => [ 1350000.0, "Map window via parent (25 kids)" ],
|
||||
'unmap' => [ 3360000.0, "Unmap window via parent (25 kids)" ],
|
||||
'destroy' => [ 1190000.0, "Destroy window via parent (25 kids)" ],
|
||||
'popup' => [ 660000.0, "Hide/expose window via popup (25 kids)" ],
|
||||
'move' => [ 120000.0, "Move window (25 kids)" ],
|
||||
'umove' => [ 1990000.0, "Moved unmapped window (25 kids)" ],
|
||||
'movetree' => [ 877000.0, "Move window via parent (25 kids)" ],
|
||||
'resize' => [ 136000.0, "Resize window (25 kids)" ],
|
||||
'uresize' => [ 1870000.0, "Resize unmapped window (25 kids)" ],
|
||||
'circulate' => [ 56300.0, "Circulate window (25 kids)" ],
|
||||
'ucirculate' => [ 3630000.0, "Circulate Unmapped window (25 kids)" ],
|
||||
};
|
||||
|
||||
|
||||
# This array defines named groups of tests. This is designed to allow
|
||||
# for simpler runs of related tests.
|
||||
#
|
||||
# Note that this array does *not* include all the x11perf tests. The idea
|
||||
# here is to run a representative sampling of the available tests, to get
|
||||
# a general idea of a system's performance, without taking forever to
|
||||
# do it. If you want to do detailed analysis of an X server or graphics
|
||||
# chip, then use x11perf directly.
|
||||
my $testGroups = {
|
||||
'rects' => [ "rect10", "rect100", "oddtilerect10", "eschertilerect100" ],
|
||||
'lines' => [ "seg100c3", "wvseg100", "ddline100", "worect500" ],
|
||||
'circle' => [ "circle500", "wddcircle100", "wpcircle100", "fspcircle100" ],
|
||||
'ellipse' => [ "ddellipse100", "wddellipse100", "pellipse10", "fspellipse100" ],
|
||||
'shapes' => [ "triangle10", "trap300", "oddostrap300", "eschertiletrap300" ],
|
||||
'aashapes' => [ "aa4trap300", "aa1trap10", "aatrap2x300", "addaatrapezoid300" ],
|
||||
'polys' => [ "complex10", "64poly100convex", "64poly10complex", "64poly100complex" ],
|
||||
'text' => [ "polytext16", "rgb24text", "caa10text", "ca24text" ],
|
||||
'blit' => [ "scroll100", "copypixwin10", "deepcopyplane10", "putimagexy500" ],
|
||||
'window' => [ "popup", "move", "movetree", "resize" ],
|
||||
};
|
||||
|
||||
|
||||
############################################################################
|
||||
# CODE
|
||||
############################################################################
|
||||
|
||||
# Exec the given command, and catch its standard output.
|
||||
# We return an array containing the PID and the filehandle on the
|
||||
# process' standard output. It's up to the caller to wait for the command
|
||||
# to terminate.
|
||||
sub command {
|
||||
my ( $cmd ) = @_;
|
||||
|
||||
my $pid = open(my $childFd, "-|");
|
||||
if (!defined($pid)) {
|
||||
die("Run: fork() failed (undef)\n");
|
||||
} elsif ($pid == 0) {
|
||||
exec($cmd);
|
||||
die("Run: exec() failed (returned)\n");
|
||||
}
|
||||
|
||||
return ( $pid, $childFd );
|
||||
}
|
||||
|
||||
|
||||
# Get data from running a system command. Used for things like getting
|
||||
# the host OS from `uname -o` etc.
|
||||
#
|
||||
# Ignores initial blank lines from the command and returns the first
|
||||
# non-blank line, with white space trimmed off.
|
||||
sub runTest {
|
||||
my ( $test, $reps, $time ) = @_;
|
||||
|
||||
my $tdata = $testData->{$test};
|
||||
if (!defined($tdata)) {
|
||||
printf STDERR "gfx-x11: No such test: %s\n", $test;
|
||||
exit(9);
|
||||
}
|
||||
|
||||
my $cmd = sprintf "x11perf -repeat %d -subs 25 -time %d -%s",
|
||||
$reps, $time, $test;
|
||||
my ( $pid, $fd ) = command($cmd);
|
||||
my $average = 0;
|
||||
while (<$fd>) {
|
||||
chomp;
|
||||
|
||||
# Display the output for logging.
|
||||
printf "%s\n", $_;
|
||||
|
||||
# Save the score.
|
||||
my ( $reps, $per, $rate ) =
|
||||
( m:([0-9]+)\s+trep\s+@\s+([0-9.]+)\s+msec\s+\(\s*([0-9.]+)/sec\): );
|
||||
$average = $rate if (defined($rate));
|
||||
}
|
||||
|
||||
# Close the command and wait for it to die. Bomb out if it failed.
|
||||
# close($fd);
|
||||
my $p = waitpid($pid, 0);
|
||||
my $status = $?;
|
||||
exit($status) if ($status != 0);
|
||||
|
||||
# Calculate and return the weighted result.
|
||||
my $score = $average / $tdata->[0] * 1000.0;
|
||||
printf "Test %s: %d --> %.1f\n", $test, $average, $score;
|
||||
return $score;
|
||||
}
|
||||
|
||||
|
||||
sub runGroup {
|
||||
my ( $group, $reps, $time ) = @_;
|
||||
|
||||
my $gdata = $testGroups->{$group};
|
||||
if (!defined($gdata)) {
|
||||
printf STDERR "gfx-x11: No such test group: %s\n", $group;
|
||||
exit(9);
|
||||
}
|
||||
|
||||
my $count = 0;
|
||||
my $total = 0;
|
||||
foreach my $test (@$gdata) {
|
||||
$total += runTest($test, $reps, $time);
|
||||
++$count;
|
||||
}
|
||||
$total /= $count;
|
||||
|
||||
$total;
|
||||
}
|
||||
|
||||
|
||||
############################################################################
|
||||
# MAIN
|
||||
############################################################################
|
||||
|
||||
sub main {
|
||||
my @args = @_;
|
||||
|
||||
if (scalar(@args) < 3) {
|
||||
printf STDERR "Usage: gfx-x11 group reps time\n";
|
||||
exit(9);
|
||||
}
|
||||
|
||||
my $reps = $args[1];
|
||||
my $time = $args[2];
|
||||
|
||||
my $score = runGroup($args[0], $reps, $time);
|
||||
printf STDERR "COUNT|%.1f|0|score\n", $score;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
exit(main(@ARGV));
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
# Baseline benchmark scores, used for calculating index results.
|
||||
|
||||
# Scores from "George", a SPARCstation 20-61.
|
||||
dhry2reg|10|lps|116700|116700|2
|
||||
whetstone-double|10|MWIPS|55.0|55.0|2
|
||||
execl|20|lps|43.0|43.0|1
|
||||
fstime|20|KBps|3960|3960|1
|
||||
fsbuffer|20|KBps|1655|1655|1
|
||||
fsdisk|20|KBps|5800|5800|1
|
||||
pipe|10|lps|12440|12440|2
|
||||
context1|10|lps|4000|4000|2
|
||||
spawn|20|lps|126|126|1
|
||||
shell8|60|lpm|6|6|1
|
||||
syscall|10|lps|15000|15000|2
|
||||
|
||||
# The shell1 test was added to the index in 5.0, and this baseline score
|
||||
# was extrapolated to roughly match George's performance.
|
||||
shell1|60|lpm|42.4|42.4|1
|
||||
|
||||
# The 2D baseline scores were derived from a test run on an HP Compaq nc8430
|
||||
# with an ATI Mobility Radeon X1600 Video (256MB) — this is a fairly
|
||||
# common modern adaptor with 3D. The baseline scores here are then
|
||||
# 1/66.6 of the values from that run, to bring them roughly in line with
|
||||
# George. (The HP has an index score of 666.6 single-process.)
|
||||
2d-rects|3|score|15|15|1
|
||||
#2d-lines|3|score|15|15|1
|
||||
#2d-circle|3|score|15|15|1
|
||||
2d-ellipse|3|score|15|15|1
|
||||
#2d-shapes|3|score|15|15|1
|
||||
2d-aashapes|3|score|15|15|1
|
||||
#2d-polys|3|score|15|15|1
|
||||
2d-text|3|score|15|15|1
|
||||
2d-blit|3|score|15|15|1
|
||||
2d-window|3|score|15|15|1
|
||||
|
||||
# The gears test score is derived from a test run on an HP Compaq nc8430
|
||||
# with an ATI Mobility Radeon X1600 Video (256MB) — this is a fairly
|
||||
# common modern adaptor with 3D. The baseline scores here are then
|
||||
# 1/66.6 of the values from that run, to bring them roughly in line with
|
||||
# George.
|
||||
ubgears|20|fps|33.4|33.4|3
|
||||
|
||||
# The grep and sysexec tests were added in 5.1.1; they are not index tests,
|
||||
# but these baseline scores were added for convenience.
|
||||
grep|30|lpm|1|1|3
|
||||
sysexec|10|lps|25|25|10
|
||||
@@ -1,23 +0,0 @@
|
||||
#! /bin/sh
|
||||
###############################################################################
|
||||
# The BYTE UNIX Benchmarks - Release 3
|
||||
# Module: multi.sh SID: 3.4 5/15/91 19:30:24
|
||||
#
|
||||
###############################################################################
|
||||
# Bug reports, patches, comments, suggestions should be sent to:
|
||||
#
|
||||
# Ben Smith or Rick Grehan at BYTE Magazine
|
||||
# ben@bytepb.UUCP rick_g@bytepb.UUCP
|
||||
#
|
||||
###############################################################################
|
||||
# Modification Log:
|
||||
#
|
||||
###############################################################################
|
||||
ID="@(#)multi.sh:3.4 -- 5/15/91 19:30:24";
|
||||
instance=1
|
||||
while [ $instance -le $1 ]; do
|
||||
/bin/sh "$UB_BINDIR/tst.sh" &
|
||||
instance=`expr $instance + 1`
|
||||
done
|
||||
wait
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /bin/sh
|
||||
###############################################################################
|
||||
# The BYTE UNIX Benchmarks - Release 3
|
||||
# Module: tst.sh SID: 3.4 5/15/91 19:30:24
|
||||
#
|
||||
###############################################################################
|
||||
# Bug reports, patches, comments, suggestions should be sent to:
|
||||
#
|
||||
# Ben Smith or Rick Grehan at BYTE Magazine
|
||||
# ben@bytepb.UUCP rick_g@bytepb.UUCP
|
||||
#
|
||||
###############################################################################
|
||||
# Modification Log:
|
||||
#
|
||||
###############################################################################
|
||||
ID="@(#)tst.sh:3.4 -- 5/15/91 19:30:24";
|
||||
sort >sort.$$ <sort.src
|
||||
grep the sort.$$ | tee grep.$$ | wc > wc.$$
|
||||
rm sort.$$ grep.$$ wc.$$
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
# # # # # # # ##### ###### # # #### # #
|
||||
# # ## # # # # # # # ## # # # # #
|
||||
# # # # # # ## ##### ##### # # # # ######
|
||||
# # # # # # ## # # # # # # # # #
|
||||
# # # ## # # # # # # # ## # # # #
|
||||
#### # # # # # ##### ###### # # #### # #
|
||||
|
||||
Version 5.1.2 Based on the Byte Magazine Unix Benchmark
|
||||
|
||||
Multi-CPU version Version 5 revisions by Ian Smith,
|
||||
Sunnyvale, CA, USA
|
||||
December 22, 2007 johantheghost at yahoo period com
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
export CC=cc
|
||||
export MINIX=1
|
||||
./Run
|
||||
@@ -1,108 +0,0 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: arith.c SID: 3.3 5/15/91 19:30:19
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* May 12, 1989 - modified empty loops to avoid nullifying by optimizing
|
||||
* compilers
|
||||
* August 28, 1990 - changed timing relationship--now returns total number
|
||||
* of iterations (ty)
|
||||
* November 9, 1990 - made changes suggested by Keith Cantrell
|
||||
* (digi!kcantrel) to defeat optimization
|
||||
* to non-existence
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
char SCCSid[] = "@(#) @(#)arith.c:3.3 -- 5/15/91 19:30:19";
|
||||
/*
|
||||
* arithmetic test
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "timeit.c"
|
||||
|
||||
int dumb_stuff(int);
|
||||
|
||||
unsigned long iter;
|
||||
|
||||
/* this function is called when the alarm expires */
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%ld|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int duration;
|
||||
int result = 0;
|
||||
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
|
||||
/* set up alarm call */
|
||||
iter = 0; /* init iteration count */
|
||||
wake_me(duration, report);
|
||||
|
||||
/* this loop will be interrupted by the alarm call */
|
||||
while (1)
|
||||
{
|
||||
/* in switching to time-based (instead of iteration-based),
|
||||
the following statement was added. It should not skew
|
||||
the timings too much--there was an increment and test
|
||||
in the "while" expression above. The only difference is
|
||||
that now we're incrementing a long instead of an int. (ty) */
|
||||
++iter;
|
||||
/* the loop calls a function to insure that something is done
|
||||
the results of the function are fed back in (just so they
|
||||
they won't be thrown away. A loop with
|
||||
unused assignments may get optimized out of existence */
|
||||
result = dumb_stuff(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************** dumb_stuff *******************/
|
||||
int dumb_stuff(i)
|
||||
int i;
|
||||
{
|
||||
#ifndef arithoh
|
||||
datum x, y, z;
|
||||
z = 0;
|
||||
#endif
|
||||
/*
|
||||
* 101
|
||||
* sum i*i/(i*i-1)
|
||||
* i=2
|
||||
*/
|
||||
/* notice that the i value is always reset by the loop */
|
||||
for (i=2; i<=101; i++)
|
||||
{
|
||||
#ifndef arithoh
|
||||
x = i;
|
||||
y = x*x;
|
||||
z += y/(y-1);
|
||||
}
|
||||
return(x+y+z);
|
||||
#else
|
||||
}
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,595 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: big.c SID: 3.3 5/15/91 19:30:18
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
/*
|
||||
* dummy code for execl test [ old version of makework.c ]
|
||||
*
|
||||
* makework [ -r rate ] [ -c copyfile ] nusers
|
||||
*
|
||||
* job streams are specified on standard input with lines of the form
|
||||
* full_path_name_for_command [ options ] [ <standard_input_file ]
|
||||
*
|
||||
* "standard input" is send to all nuser instances of the commands in the
|
||||
* job streams at a rate not in excess of "rate" characters per second
|
||||
* per command
|
||||
*
|
||||
*/
|
||||
/* this code is included in other files and therefore has no SCCSid */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
#define DEF_RATE 5.0
|
||||
#define GRANULE 5
|
||||
#define CHUNK 60
|
||||
#define MAXCHILD 12
|
||||
#define MAXWORK 10
|
||||
|
||||
/* Can't seem to get this declared in the headers... */
|
||||
extern int kill(pid_t pid, int sig);
|
||||
|
||||
void wrapup(char *);
|
||||
void onalarm(int);
|
||||
void pipeerr(int sig);
|
||||
void grunt(int sig);
|
||||
void getwork(void);
|
||||
#if debug
|
||||
void dumpwork(void);
|
||||
#endif
|
||||
void fatal(char *s);
|
||||
|
||||
float thres;
|
||||
float est_rate = DEF_RATE;
|
||||
int nusers; /* number of concurrent users to be simulated by
|
||||
* this process */
|
||||
int firstuser; /* ordinal identification of first user for this
|
||||
* process */
|
||||
int nwork = 0; /* number of job streams */
|
||||
int exit_status = 0; /* returned to parent */
|
||||
int sigpipe; /* pipe write error flag */
|
||||
|
||||
struct st_work {
|
||||
char *cmd; /* name of command to run */
|
||||
char **av; /* arguments to command */
|
||||
char *input; /* standard input buffer */
|
||||
int inpsize; /* size of standard input buffer */
|
||||
char *outf; /* standard output (filename) */
|
||||
} work[MAXWORK];
|
||||
|
||||
struct {
|
||||
int xmit; /* # characters sent */
|
||||
char *bp; /* std input buffer pointer */
|
||||
int blen; /* std input buffer length */
|
||||
int fd; /* stdin to command */
|
||||
int pid; /* child PID */
|
||||
char *line; /* start of input line */
|
||||
int firstjob; /* inital piece of work */
|
||||
int thisjob; /* current piece of work */
|
||||
} child[MAXCHILD], *cp;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int l;
|
||||
int fcopy = 0; /* fd for copy output */
|
||||
int master = 1; /* the REAL master, == 0 for clones */
|
||||
int nchild; /* no. of children for a clone to run */
|
||||
int done; /* count of children finished */
|
||||
int output; /* aggregate output char count for all
|
||||
children */
|
||||
int c;
|
||||
int thiswork = 0; /* next job stream to allocate */
|
||||
int nch; /* # characters to write */
|
||||
int written; /* # characters actully written */
|
||||
char logname[15]; /* name of the log file(s) */
|
||||
int pvec[2]; /* for pipes */
|
||||
char *p;
|
||||
char *prog; /* my name */
|
||||
|
||||
#if ! debug
|
||||
freopen("masterlog.00", "a", stderr);
|
||||
#endif
|
||||
prog = argv[0];
|
||||
while (argc > 1 && argv[1][0] == '-') {
|
||||
p = &argv[1][1];
|
||||
argc--;
|
||||
argv++;
|
||||
while (*p) {
|
||||
switch (*p) {
|
||||
case 'r':
|
||||
est_rate = atoi(argv[1]);
|
||||
sscanf(argv[1], "%f", &est_rate);
|
||||
if (est_rate <= 0) {
|
||||
fprintf(stderr, "%s: bad rate, reset to %.2f chars/sec\n", prog, DEF_RATE);
|
||||
est_rate = DEF_RATE;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
fcopy = open(argv[1], 1);
|
||||
if (fcopy < 0)
|
||||
fcopy = creat(argv[1], 0600);
|
||||
if (fcopy < 0) {
|
||||
fprintf(stderr, "%s: cannot open copy file '%s'\n",
|
||||
prog, argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
lseek(fcopy, 0L, 2); /* append at end of file */
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
|
||||
exit(4);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: missing nusers\n", prog);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
nusers = atoi(argv[1]);
|
||||
if (nusers < 1) {
|
||||
fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
|
||||
exit(4);
|
||||
}
|
||||
fprintf(stderr, "%d Users\n", nusers);
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* build job streams */
|
||||
getwork();
|
||||
#if debug
|
||||
dumpwork();
|
||||
#endif
|
||||
|
||||
/* clone copies of myself to run up to MAXCHILD jobs each */
|
||||
firstuser = MAXCHILD;
|
||||
fprintf(stderr, "master pid %d\n", getpid());
|
||||
fflush(stderr);
|
||||
while (nusers > MAXCHILD) {
|
||||
fflush(stderr);
|
||||
if (nusers >= 2*MAXCHILD)
|
||||
/* the next clone must run MAXCHILD jobs */
|
||||
nchild = MAXCHILD;
|
||||
else
|
||||
/* the next clone must run the leftover jobs */
|
||||
nchild = nusers - MAXCHILD;
|
||||
if ((l = fork()) == -1) {
|
||||
/* fork failed */
|
||||
fatal("** clone fork failed **\n");
|
||||
goto bepatient;
|
||||
} else if (l > 0) {
|
||||
fprintf(stderr, "master clone pid %d\n", l);
|
||||
/* I am the master with nchild fewer jobs to run */
|
||||
nusers -= nchild;
|
||||
firstuser += MAXCHILD;
|
||||
continue;
|
||||
} else {
|
||||
/* I am a clone, run MAXCHILD jobs */
|
||||
#if ! debug
|
||||
sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
|
||||
freopen(logname, "w", stderr);
|
||||
#endif
|
||||
master = 0;
|
||||
nusers = nchild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (master)
|
||||
firstuser = 0;
|
||||
|
||||
close(0);
|
||||
for (i = 0; i < nusers; i++ ) {
|
||||
fprintf(stderr, "user %d job %d ", firstuser+i, thiswork);
|
||||
if (pipe(pvec) == -1) {
|
||||
/* this is fatal */
|
||||
fatal("** pipe failed **\n");
|
||||
goto bepatient;
|
||||
}
|
||||
fflush(stderr);
|
||||
if ((child[i].pid = fork()) == 0) {
|
||||
int fd;
|
||||
/* the command */
|
||||
if (pvec[0] != 0) {
|
||||
close(0);
|
||||
dup(pvec[0]);
|
||||
}
|
||||
#if ! debug
|
||||
sprintf(logname, "userlog.%02d", firstuser+i);
|
||||
freopen(logname, "w", stderr);
|
||||
#endif
|
||||
for (fd = 3; fd < 24; fd++)
|
||||
close(fd);
|
||||
if (work[thiswork].outf[0] != '\0') {
|
||||
/* redirect std output */
|
||||
char *q;
|
||||
for (q = work[thiswork].outf; *q != '\n'; q++) ;
|
||||
*q = '\0';
|
||||
if (freopen(work[thiswork].outf, "w", stdout) == NULL) {
|
||||
fprintf(stderr, "makework: cannot open %s for std output\n",
|
||||
work[thiswork].outf);
|
||||
fflush(stderr);
|
||||
}
|
||||
*q = '\n';
|
||||
}
|
||||
execv(work[thiswork].cmd, work[thiswork].av);
|
||||
/* don't expect to get here! */
|
||||
fatal("** exec failed **\n");
|
||||
goto bepatient;
|
||||
}
|
||||
else if (child[i].pid == -1) {
|
||||
fatal("** fork failed **\n");
|
||||
goto bepatient;
|
||||
}
|
||||
else {
|
||||
close(pvec[0]);
|
||||
child[i].fd = pvec[1];
|
||||
child[i].line = child[i].bp = work[thiswork].input;
|
||||
child[i].blen = work[thiswork].inpsize;
|
||||
child[i].thisjob = thiswork;
|
||||
child[i].firstjob = thiswork;
|
||||
fprintf(stderr, "pid %d pipe fd %d", child[i].pid, child[i].fd);
|
||||
if (work[thiswork].outf[0] != '\0') {
|
||||
char *q;
|
||||
fprintf(stderr, " > ");
|
||||
for (q=work[thiswork].outf; *q != '\n'; q++)
|
||||
fputc(*q, stderr);
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
thiswork++;
|
||||
if (thiswork >= nwork)
|
||||
thiswork = 0;
|
||||
}
|
||||
}
|
||||
fflush(stderr);
|
||||
|
||||
srand(time(0));
|
||||
thres = 0;
|
||||
done = output = 0;
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (child[i].blen == 0)
|
||||
done++;
|
||||
else
|
||||
thres += est_rate * GRANULE;
|
||||
}
|
||||
est_rate = thres;
|
||||
|
||||
signal(SIGALRM, onalarm);
|
||||
signal(SIGPIPE, pipeerr);
|
||||
alarm(GRANULE);
|
||||
while (done < nusers) {
|
||||
for (i = 0; i < nusers; i++) {
|
||||
cp = &child[i];
|
||||
if (cp->xmit >= cp->blen) continue;
|
||||
l = rand() % CHUNK + 1; /* 1-CHUNK chars */
|
||||
if (l == 0) continue;
|
||||
if (cp->xmit + l > cp->blen)
|
||||
l = cp->blen - cp->xmit;
|
||||
p = cp->bp;
|
||||
cp->bp += l;
|
||||
cp->xmit += l;
|
||||
#if debug
|
||||
fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
|
||||
#endif
|
||||
while (p < cp->bp) {
|
||||
if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
|
||||
/* write it out */
|
||||
nch = p - cp->line + 1;
|
||||
if ((written = write(cp->fd, cp->line, nch)) != nch) {
|
||||
/* argh! */
|
||||
cp->line[nch] = '\0';
|
||||
fprintf(stderr, "user %d job %d cmd %s ",
|
||||
firstuser+i, cp->thisjob, cp->line);
|
||||
fprintf(stderr, "write(,,%d) returns %d\n", nch, written);
|
||||
if (sigpipe)
|
||||
fatal("** SIGPIPE error **\n");
|
||||
else
|
||||
fatal("** write error **\n");
|
||||
goto bepatient;
|
||||
|
||||
}
|
||||
if (fcopy)
|
||||
write(fcopy, cp->line, p - cp->line + 1);
|
||||
#if debug
|
||||
fprintf(stderr, "child %d gets \"", i);
|
||||
{
|
||||
char *q = cp->line;
|
||||
while (q <= p) {
|
||||
if (*q >= ' ' && *q <= '~')
|
||||
fputc(*q, stderr);
|
||||
else
|
||||
fprintf(stderr, "\\%03o", *q);
|
||||
q++;
|
||||
}
|
||||
}
|
||||
fputc('"', stderr);
|
||||
#endif
|
||||
cp->line = &p[1];
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (cp->xmit >= cp->blen) {
|
||||
done++;
|
||||
close(cp->fd);
|
||||
#if debug
|
||||
fprintf(stderr, "child %d, close std input\n", i);
|
||||
#endif
|
||||
}
|
||||
output += l;
|
||||
}
|
||||
while (output > thres) {
|
||||
pause();
|
||||
#if debug
|
||||
fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bepatient:
|
||||
alarm(0);
|
||||
/****
|
||||
* If everything is going OK, we should simply be able to keep
|
||||
* looping unitil 'wait' fails, however some descendent process may
|
||||
* be in a state from which it can never exit, and so a timeout
|
||||
* is used.
|
||||
* 5 minutes should be ample, since the time to run all jobs is of
|
||||
* the order of 5-10 minutes, however some machines are painfully slow,
|
||||
* so the timeout has been set at 20 minutes (1200 seconds).
|
||||
****/
|
||||
signal(SIGALRM, grunt);
|
||||
alarm(1200);
|
||||
while ((c = wait(&l)) != -1) {
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (c == child[i].pid) {
|
||||
fprintf(stderr, "user %d job %d pid %d done", firstuser+i, child[i].thisjob, c);
|
||||
if (l != 0) {
|
||||
if (l & 0x7f)
|
||||
fprintf(stderr, " status %d", l & 0x7f);
|
||||
if (l & 0xff00)
|
||||
fprintf(stderr, " exit code %d", (l>>8) & 0xff);
|
||||
exit_status = 4;
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
c = child[i].pid = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c != -1) {
|
||||
fprintf(stderr, "master clone done, pid %d ", c);
|
||||
if (l != 0) {
|
||||
if (l & 0x7f)
|
||||
fprintf(stderr, " status %d", l & 0x7f);
|
||||
if (l & 0xff00)
|
||||
fprintf(stderr, " exit code %d", (l>>8) & 0xff);
|
||||
exit_status = 4;
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
alarm(0);
|
||||
wrapup("Finished waiting ...");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void onalarm(int foo)
|
||||
{
|
||||
thres += est_rate;
|
||||
signal(SIGALRM, onalarm);
|
||||
alarm(GRANULE);
|
||||
}
|
||||
|
||||
void grunt(int sig)
|
||||
{
|
||||
/* timeout after label "bepatient" in main */
|
||||
exit_status = 4;
|
||||
wrapup("Timed out waiting for jobs to finish ...");
|
||||
}
|
||||
|
||||
void pipeerr(int sig)
|
||||
{
|
||||
sigpipe++;
|
||||
}
|
||||
|
||||
void wrapup(char *reason)
|
||||
{
|
||||
int i;
|
||||
int killed = 0;
|
||||
fflush(stderr);
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
|
||||
if (!killed) {
|
||||
killed++;
|
||||
fprintf(stderr, "%s\n", reason);
|
||||
fflush(stderr);
|
||||
}
|
||||
fprintf(stderr, "user %d job %d pid %d killed off\n", firstuser+i, child[i].thisjob, child[i].pid);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
exit(exit_status);
|
||||
}
|
||||
|
||||
#define MAXLINE 512
|
||||
void getwork(void)
|
||||
{
|
||||
int i;
|
||||
int f;
|
||||
int ac=0;
|
||||
char *lp = (void *)0;
|
||||
char *q = (void *)0;
|
||||
struct st_work *w = (void *)0;
|
||||
char line[MAXLINE];
|
||||
char c;
|
||||
|
||||
while (fgets(line, MAXLINE, stdin) != NULL) {
|
||||
if (nwork >= MAXWORK) {
|
||||
fprintf(stderr, "Too many jobs specified, .. increase MAXWORK\n");
|
||||
exit(4);
|
||||
}
|
||||
w = &work[nwork];
|
||||
lp = line;
|
||||
i = 1;
|
||||
while (*lp && *lp != ' ') {
|
||||
i++;
|
||||
lp++;
|
||||
}
|
||||
w->cmd = (char *)malloc(i);
|
||||
strncpy(w->cmd, line, i-1);
|
||||
w->cmd[i-1] = '\0';
|
||||
w->inpsize = 0;
|
||||
w->input = "";
|
||||
/* start to build arg list */
|
||||
ac = 2;
|
||||
w->av = (char **)malloc(2*sizeof(char *));
|
||||
q = w->cmd;
|
||||
while (*q) q++;
|
||||
q--;
|
||||
while (q >= w->cmd) {
|
||||
if (*q == '/') {
|
||||
q++;
|
||||
break;
|
||||
}
|
||||
q--;
|
||||
}
|
||||
w->av[0] = q;
|
||||
while (*lp) {
|
||||
if (*lp == ' ') {
|
||||
/* space */
|
||||
lp++;
|
||||
continue;
|
||||
}
|
||||
else if (*lp == '<') {
|
||||
/* standard input for this job */
|
||||
q = ++lp;
|
||||
while (*lp && *lp != ' ') lp++;
|
||||
c = *lp;
|
||||
*lp = '\0';
|
||||
if ((f = open(q, 0)) == -1) {
|
||||
fprintf(stderr, "cannot open input file (%s) for job %d\n",
|
||||
q, nwork);
|
||||
exit(4);
|
||||
}
|
||||
/* gobble input */
|
||||
w->input = (char *)malloc(512);
|
||||
while ((i = read(f, &w->input[w->inpsize], 512)) > 0) {
|
||||
w->inpsize += i;
|
||||
w->input = (char *)realloc(w->input, w->inpsize+512);
|
||||
}
|
||||
w->input = (char *)realloc(w->input, w->inpsize);
|
||||
close(f);
|
||||
/* extract stdout file name from line beginning "C=" */
|
||||
w->outf = "";
|
||||
for (q = w->input; q < &w->input[w->inpsize-10]; q++) {
|
||||
if (*q == '\n' && strncmp(&q[1], "C=", 2) == 0) {
|
||||
w->outf = &q[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if debug
|
||||
if (*w->outf) {
|
||||
fprintf(stderr, "stdout->");
|
||||
for (q=w->outf; *q != '\n'; q++)
|
||||
fputc(*q, stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* a command option */
|
||||
ac++;
|
||||
w->av = (char **)realloc(w->av, ac*sizeof(char *));
|
||||
q = lp;
|
||||
i = 1;
|
||||
while (*lp && *lp != ' ') {
|
||||
lp++;
|
||||
i++;
|
||||
}
|
||||
w->av[ac-2] = (char *)malloc(i);
|
||||
strncpy(w->av[ac-2], q, i-1);
|
||||
w->av[ac-2][i-1] = '\0';
|
||||
}
|
||||
}
|
||||
w->av[ac-1] = (char *)0;
|
||||
nwork++;
|
||||
}
|
||||
}
|
||||
|
||||
#if debug
|
||||
void dumpwork(void)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < nwork; i++) {
|
||||
fprintf(stderr, "job %d: cmd: %s\n", i, work[i].cmd);
|
||||
j = 0;
|
||||
while (work[i].av[j]) {
|
||||
fprintf(stderr, "argv[%d]: %s\n", j, work[i].av[j]);
|
||||
j++;
|
||||
}
|
||||
fprintf(stderr, "input: %d chars text: ", work[i].inpsize);
|
||||
if (work[i].input == (char *)0)
|
||||
fprintf(stderr, "<NULL>\n");
|
||||
else {
|
||||
register char *pend;
|
||||
char *p;
|
||||
char c;
|
||||
p = work[i].input;
|
||||
while (*p) {
|
||||
pend = p;
|
||||
while (*pend && *pend != '\n')
|
||||
pend++;
|
||||
c = *pend;
|
||||
*pend = '\0';
|
||||
fprintf(stderr, "%s\n", p);
|
||||
*pend = c;
|
||||
p = &pend[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void fatal(char *s)
|
||||
{
|
||||
int i;
|
||||
fprintf(stderr, s);
|
||||
fflush(stderr);
|
||||
perror("Reason?");
|
||||
fflush(stderr);
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1) {
|
||||
fprintf(stderr, "pid %d killed off\n", child[i].pid);
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
exit_status = 4;
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: context1.c SID: 3.3 5/15/91 19:30:18
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: context1.c,v 3.4 87/06/22 14:22:59 kjmcdonell Beta $
|
||||
* August 28, 1990 - changed timing routines--now returns total number of
|
||||
* iterations in specified time period
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)context1.c:3.3 -- 5/15/91 19:30:18";
|
||||
/*
|
||||
* Context switching via synchronized unbuffered pipe i/o
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef MINIX
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#ifdef LINUX
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long iter;
|
||||
#ifdef MINIX
|
||||
pid_t child;
|
||||
#endif
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr, "COUNT|%lu|1|lps\n", iter);
|
||||
#ifdef MINIX
|
||||
kill(child, SIGKILL);
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int duration;
|
||||
unsigned long check;
|
||||
int p1[2], p2[2];
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: context duration\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
|
||||
/* set up alarm call */
|
||||
iter = 0;
|
||||
wake_me(duration, report);
|
||||
|
||||
if (pipe(p1) || pipe(p2)) {
|
||||
perror("pipe create failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef MINIX
|
||||
if (fork()) { /* parent process */
|
||||
#else
|
||||
if ((child = fork())) {
|
||||
#endif
|
||||
/* master, write p1 & read p2 */
|
||||
close(p1[0]); close(p2[1]);
|
||||
while (1) {
|
||||
if (write(p1[1], (char *)&iter, sizeof(iter)) != sizeof(iter)) {
|
||||
if ((errno != 0) && (errno != EINTR))
|
||||
perror("master write failed");
|
||||
exit(1);
|
||||
}
|
||||
if (read(p2[0], (char *)&check, sizeof(check)) != sizeof(check)) {
|
||||
if ((errno != 0) && (errno != EINTR))
|
||||
perror("master read failed");
|
||||
exit(1);
|
||||
}
|
||||
if (check != iter) {
|
||||
fprintf(stderr, "Master sync error: expect %lu, got %lu\n",
|
||||
iter, check);
|
||||
exit(2);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
else { /* child process */
|
||||
unsigned long iter1;
|
||||
|
||||
iter1 = 0;
|
||||
/* slave, read p1 & write p2 */
|
||||
close(p1[1]); close(p2[0]);
|
||||
while (1) {
|
||||
if (read(p1[0], (char *)&check, sizeof(check)) != sizeof(check)) {
|
||||
if ((errno != 0) && (errno != EINTR))
|
||||
perror("slave read failed");
|
||||
exit(1);
|
||||
}
|
||||
if (check != iter1) {
|
||||
fprintf(stderr, "Slave sync error: expect %lu, got %lu\n",
|
||||
iter, check);
|
||||
exit(2);
|
||||
}
|
||||
if (write(p2[1], (char *)&iter1, sizeof(iter1)) != sizeof(check)) {
|
||||
if ((errno != 0) && (errno != EINTR))
|
||||
perror("slave write failed");
|
||||
exit(1);
|
||||
}
|
||||
iter1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,435 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: dhry.h SID: 3.4 5/15/91 19:30:21
|
||||
*
|
||||
*****************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*****************************************************************************
|
||||
* Modification Log:
|
||||
* addapted from:
|
||||
*
|
||||
*
|
||||
* "DHRYSTONE" Benchmark Program
|
||||
* -----------------------------
|
||||
*
|
||||
* Version: C, Version 2.1
|
||||
*
|
||||
* File: dhry.h (part 1 of 3)
|
||||
*
|
||||
* Date: May 25, 1988
|
||||
*
|
||||
* Author: Reinhold P. Weicker
|
||||
* Siemens AG, AUT E 51
|
||||
* Postfach 3220
|
||||
* 8520 Erlangen
|
||||
* Germany (West)
|
||||
* Phone: [+49]-9131-7-20330
|
||||
* (8-17 Central European Time)
|
||||
* Usenet: ..!mcvax!unido!estevax!weicker
|
||||
*
|
||||
* Original Version (in Ada) published in
|
||||
* "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
|
||||
* pp. 1013 - 1030, together with the statistics
|
||||
* on which the distribution of statements etc. is based.
|
||||
*
|
||||
* In this C version, the following C library functions are used:
|
||||
* - strcpy, strcmp (inside the measurement loop)
|
||||
* - printf, scanf (outside the measurement loop)
|
||||
* In addition, Berkeley UNIX system calls "times ()" or "time ()"
|
||||
* are used for execution time measurement. For measurements
|
||||
* on other systems, these calls have to be changed.
|
||||
*
|
||||
* Collection of Results:
|
||||
* Reinhold Weicker (address see above) and
|
||||
*
|
||||
* Rick Richardson
|
||||
* PC Research. Inc.
|
||||
* 94 Apple Orchard Drive
|
||||
* Tinton Falls, NJ 07724
|
||||
* Phone: (201) 834-1378 (9-17 EST)
|
||||
* Usenet: ...!seismo!uunet!pcrat!rick
|
||||
*
|
||||
* Please send results to Rick Richardson and/or Reinhold Weicker.
|
||||
* Complete information should be given on hardware and software used.
|
||||
* Hardware information includes: Machine type, CPU, type and size
|
||||
* of caches; for microprocessors: clock frequency, memory speed
|
||||
* (number of wait states).
|
||||
* Software information includes: Compiler (and runtime library)
|
||||
* manufacturer and version, compilation switches, OS version.
|
||||
* The Operating System version may give an indication about the
|
||||
* compiler; Dhrystone itself performs no OS calls in the measurement loop.
|
||||
*
|
||||
* The complete output generated by the program should be mailed
|
||||
* such that at least some checks for correctness can be made.
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* History: This version C/2.1 has been made for two reasons:
|
||||
*
|
||||
* 1) There is an obvious need for a common C version of
|
||||
* Dhrystone, since C is at present the most popular system
|
||||
* programming language for the class of processors
|
||||
* (microcomputers, minicomputers) where Dhrystone is used most.
|
||||
* There should be, as far as possible, only one C version of
|
||||
* Dhrystone such that results can be compared without
|
||||
* restrictions. In the past, the C versions distributed
|
||||
* by Rick Richardson (Version 1.1) and by Reinhold Weicker
|
||||
* had small (though not significant) differences.
|
||||
*
|
||||
* 2) As far as it is possible without changes to the Dhrystone
|
||||
* statistics, optimizing compilers should be prevented from
|
||||
* removing significant statements.
|
||||
*
|
||||
* This C version has been developed in cooperation with
|
||||
* Rick Richardson (Tinton Falls, NJ), it incorporates many
|
||||
* ideas from the "Version 1.1" distributed previously by
|
||||
* him over the UNIX network Usenet.
|
||||
* I also thank Chaim Benedelac (National Semiconductor),
|
||||
* David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
|
||||
* Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
|
||||
* for their help with comments on earlier versions of the
|
||||
* benchmark.
|
||||
*
|
||||
* Changes: In the initialization part, this version follows mostly
|
||||
* Rick Richardson's version distributed via Usenet, not the
|
||||
* version distributed earlier via floppy disk by Reinhold Weicker.
|
||||
* As a concession to older compilers, names have been made
|
||||
* unique within the first 8 characters.
|
||||
* Inside the measurement loop, this version follows the
|
||||
* version previously distributed by Reinhold Weicker.
|
||||
*
|
||||
* At several places in the benchmark, code has been added,
|
||||
* but within the measurement loop only in branches that
|
||||
* are not executed. The intention is that optimizing compilers
|
||||
* should be prevented from moving code out of the measurement
|
||||
* loop, or from removing code altogether. Since the statements
|
||||
* that are executed within the measurement loop have NOT been
|
||||
* changed, the numbers defining the "Dhrystone distribution"
|
||||
* (distribution of statements, operand types and locality)
|
||||
* still hold. Except for sophisticated optimizing compilers,
|
||||
* execution times for this version should be the same as
|
||||
* for previous versions.
|
||||
*
|
||||
* Since it has proven difficult to subtract the time for the
|
||||
* measurement loop overhead in a correct way, the loop check
|
||||
* has been made a part of the benchmark. This does have
|
||||
* an impact - though a very minor one - on the distribution
|
||||
* statistics which have been updated for this version.
|
||||
*
|
||||
* All changes within the measurement loop are described
|
||||
* and discussed in the companion paper "Rationale for
|
||||
* Dhrystone version 2".
|
||||
*
|
||||
* Because of the self-imposed limitation that the order and
|
||||
* distribution of the executed statements should not be
|
||||
* changed, there are still cases where optimizing compilers
|
||||
* may not generate code for some statements. To a certain
|
||||
* degree, this is unavoidable for small synthetic benchmarks.
|
||||
* Users of the benchmark are advised to check code listings
|
||||
* whether code is generated for all statements of Dhrystone.
|
||||
*
|
||||
* Version 2.1 is identical to version 2.0 distributed via
|
||||
* the UNIX network Usenet in March 1988 except that it corrects
|
||||
* some minor deficiencies that were found by users of version 2.0.
|
||||
* The only change within the measurement loop is that a
|
||||
* non-executed "else" part was added to the "if" statement in
|
||||
* Func_3, and a non-executed "else" part removed from Proc_3.
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* Defines: The following "Defines" are possible:
|
||||
* -DREG=register (default: Not defined)
|
||||
* As an approximation to what an average C programmer
|
||||
* might do, the "register" storage class is applied
|
||||
* (if enabled by -DREG=register)
|
||||
* - for local variables, if they are used (dynamically)
|
||||
* five or more times
|
||||
* - for parameters if they are used (dynamically)
|
||||
* six or more times
|
||||
* Note that an optimal "register" strategy is
|
||||
* compiler-dependent, and that "register" declarations
|
||||
* do not necessarily lead to faster execution.
|
||||
* -DNOSTRUCTASSIGN (default: Not defined)
|
||||
* Define if the C compiler does not support
|
||||
* assignment of structures.
|
||||
* -DNOENUMS (default: Not defined)
|
||||
* Define if the C compiler does not support
|
||||
* enumeration types.
|
||||
* -DTIMES (default)
|
||||
* -DTIME
|
||||
* The "times" function of UNIX (returning process times)
|
||||
* or the "time" function (returning wallclock time)
|
||||
* is used for measurement.
|
||||
* For single user machines, "time ()" is adequate. For
|
||||
* multi-user machines where you cannot get single-user
|
||||
* access, use the "times ()" function. If you have
|
||||
* neither, use a stopwatch in the dead of night.
|
||||
* "printf"s are provided marking the points "Start Timer"
|
||||
* and "Stop Timer". DO NOT use the UNIX "time(1)"
|
||||
* command, as this will measure the total time to
|
||||
* run this program, which will (erroneously) include
|
||||
* the time to allocate storage (malloc) and to perform
|
||||
* the initialization.
|
||||
* -DHZ=nnn
|
||||
* In Berkeley UNIX, the function "times" returns process
|
||||
* time in 1/HZ seconds, with HZ = 60 for most systems.
|
||||
* CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY
|
||||
* A VALUE.
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* Compilation model and measurement (IMPORTANT):
|
||||
*
|
||||
* This C version of Dhrystone consists of three files:
|
||||
* - dhry.h (this file, containing global definitions and comments)
|
||||
* - dhry_1.c (containing the code corresponding to Ada package Pack_1)
|
||||
* - dhry_2.c (containing the code corresponding to Ada package Pack_2)
|
||||
*
|
||||
* The following "ground rules" apply for measurements:
|
||||
* - Separate compilation
|
||||
* - No procedure merging
|
||||
* - Otherwise, compiler optimizations are allowed but should be indicated
|
||||
* - Default results are those without register declarations
|
||||
* See the companion paper "Rationale for Dhrystone Version 2" for a more
|
||||
* detailed discussion of these ground rules.
|
||||
*
|
||||
* For 16-Bit processors (e.g. 80186, 80286), times for all compilation
|
||||
* models ("small", "medium", "large" etc.) should be given if possible,
|
||||
* together with a definition of these models for the compiler system used.
|
||||
*
|
||||
**************************************************************************
|
||||
*
|
||||
* Dhrystone (C version) statistics:
|
||||
*
|
||||
* [Comment from the first distribution, updated for version 2.
|
||||
* Note that because of language differences, the numbers are slightly
|
||||
* different from the Ada version.]
|
||||
*
|
||||
* The following program contains statements of a high level programming
|
||||
* language (here: C) in a distribution considered representative:
|
||||
*
|
||||
* assignments 52 (51.0 %)
|
||||
* control statements 33 (32.4 %)
|
||||
* procedure, function calls 17 (16.7 %)
|
||||
*
|
||||
* 103 statements are dynamically executed. The program is balanced with
|
||||
* respect to the three aspects:
|
||||
*
|
||||
* - statement type
|
||||
* - operand type
|
||||
* - operand locality
|
||||
* operand global, local, parameter, or constant.
|
||||
*
|
||||
* The combination of these three aspects is balanced only approximately.
|
||||
*
|
||||
* 1. Statement Type:
|
||||
* ----------------- number
|
||||
*
|
||||
* V1 = V2 9
|
||||
* (incl. V1 = F(..)
|
||||
* V = Constant 12
|
||||
* Assignment, 7
|
||||
* with array element
|
||||
* Assignment, 6
|
||||
* with record component
|
||||
* --
|
||||
* 34 34
|
||||
*
|
||||
* X = Y +|-|"&&"|"|" Z 5
|
||||
* X = Y +|-|"==" Constant 6
|
||||
* X = X +|- 1 3
|
||||
* X = Y *|/ Z 2
|
||||
* X = Expression, 1
|
||||
* two operators
|
||||
* X = Expression, 1
|
||||
* three operators
|
||||
* --
|
||||
* 18 18
|
||||
*
|
||||
* if .... 14
|
||||
* with "else" 7
|
||||
* without "else" 7
|
||||
* executed 3
|
||||
* not executed 4
|
||||
* for ... 7 | counted every time
|
||||
* while ... 4 | the loop condition
|
||||
* do ... while 1 | is evaluated
|
||||
* switch ... 1
|
||||
* break 1
|
||||
* declaration with 1
|
||||
* initialization
|
||||
* --
|
||||
* 34 34
|
||||
*
|
||||
* P (...) procedure call 11
|
||||
* user procedure 10
|
||||
* library procedure 1
|
||||
* X = F (...)
|
||||
* function call 6
|
||||
* user function 5
|
||||
* library function 1
|
||||
* --
|
||||
* 17 17
|
||||
* ---
|
||||
* 103
|
||||
*
|
||||
* The average number of parameters in procedure or function calls
|
||||
* is 1.82 (not counting the function values as implicit parameters).
|
||||
*
|
||||
*
|
||||
* 2. Operators
|
||||
* ------------
|
||||
* number approximate
|
||||
* percentage
|
||||
*
|
||||
* Arithmetic 32 50.8
|
||||
*
|
||||
* + 21 33.3
|
||||
* - 7 11.1
|
||||
* * 3 4.8
|
||||
* / (int div) 1 1.6
|
||||
*
|
||||
* Comparison 27 42.8
|
||||
*
|
||||
* == 9 14.3
|
||||
* /= 4 6.3
|
||||
* > 1 1.6
|
||||
* < 3 4.8
|
||||
* >= 1 1.6
|
||||
* <= 9 14.3
|
||||
*
|
||||
* Logic 4 6.3
|
||||
*
|
||||
* && (AND-THEN) 1 1.6
|
||||
* | (OR) 1 1.6
|
||||
* ! (NOT) 2 3.2
|
||||
*
|
||||
* -- -----
|
||||
* 63 100.1
|
||||
*
|
||||
*
|
||||
* 3. Operand Type (counted once per operand reference):
|
||||
* ---------------
|
||||
* number approximate
|
||||
* percentage
|
||||
*
|
||||
* Integer 175 72.3 %
|
||||
* Character 45 18.6 %
|
||||
* Pointer 12 5.0 %
|
||||
* String30 6 2.5 %
|
||||
* Array 2 0.8 %
|
||||
* Record 2 0.8 %
|
||||
* --- -------
|
||||
* 242 100.0 %
|
||||
*
|
||||
* When there is an access path leading to the final operand (e.g. a record
|
||||
* component), only the final data type on the access path is counted.
|
||||
*
|
||||
*
|
||||
* 4. Operand Locality:
|
||||
* -------------------
|
||||
* number approximate
|
||||
* percentage
|
||||
*
|
||||
* local variable 114 47.1 %
|
||||
* global variable 22 9.1 %
|
||||
* parameter 45 18.6 %
|
||||
* value 23 9.5 %
|
||||
* reference 22 9.1 %
|
||||
* function result 6 2.5 %
|
||||
* constant 55 22.7 %
|
||||
* --- -------
|
||||
* 242 100.0 %
|
||||
*
|
||||
*
|
||||
* The program does not compute anything meaningful, but it is syntactically
|
||||
* and semantically correct. All variables have a value assigned to them
|
||||
* before they are used as a source operand.
|
||||
*
|
||||
* There has been no explicit effort to account for the effects of a
|
||||
* cache, or to balance the use of long or short displacements for code or
|
||||
* data.
|
||||
*
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/* Compiler and system dependent definitions: */
|
||||
|
||||
#ifndef TIME
|
||||
#define TIMES
|
||||
#endif
|
||||
/* Use times(2) time function unless */
|
||||
/* explicitly defined otherwise */
|
||||
|
||||
#ifdef TIMES
|
||||
#include <sys/types.h>
|
||||
#include <sys/times.h>
|
||||
/* for "times" */
|
||||
#endif
|
||||
|
||||
#define Mic_secs_Per_Second 1000000.0
|
||||
/* Berkeley UNIX C returns process times in seconds/HZ */
|
||||
|
||||
#ifdef NOSTRUCTASSIGN
|
||||
#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
|
||||
#else
|
||||
#define structassign(d, s) d = s
|
||||
#endif
|
||||
|
||||
#ifdef NOENUM
|
||||
#define Ident_1 0
|
||||
#define Ident_2 1
|
||||
#define Ident_3 2
|
||||
#define Ident_4 3
|
||||
#define Ident_5 4
|
||||
typedef int Enumeration;
|
||||
#else
|
||||
typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
|
||||
Enumeration;
|
||||
#endif
|
||||
/* for boolean and enumeration types in Ada, Pascal */
|
||||
|
||||
/* General definitions: */
|
||||
|
||||
#include <stdio.h>
|
||||
/* for strcpy, strcmp */
|
||||
|
||||
#define Null 0
|
||||
/* Value of a Null pointer */
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
typedef int One_Thirty;
|
||||
typedef int One_Fifty;
|
||||
typedef char Capital_Letter;
|
||||
typedef int Boolean;
|
||||
typedef char Str_30 [31];
|
||||
typedef int Arr_1_Dim [50];
|
||||
typedef int Arr_2_Dim [50] [50];
|
||||
|
||||
typedef struct record
|
||||
{
|
||||
struct record *Ptr_Comp;
|
||||
Enumeration Discr;
|
||||
union {
|
||||
struct {
|
||||
Enumeration Enum_Comp;
|
||||
int Int_Comp;
|
||||
char Str_Comp [31];
|
||||
} var_1;
|
||||
struct {
|
||||
Enumeration E_Comp_2;
|
||||
char Str_2_Comp [31];
|
||||
} var_2;
|
||||
struct {
|
||||
char Ch_1_Comp;
|
||||
char Ch_2_Comp;
|
||||
} var_3;
|
||||
} variant;
|
||||
} Rec_Type, *Rec_Pointer;
|
||||
|
||||
@@ -1,427 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: dhry_1.c SID: 3.4 5/15/91 19:30:21
|
||||
*
|
||||
*****************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* *** WARNING **** With BYTE's modifications applied, results obtained with
|
||||
* ******* this version of the Dhrystone program may not be applicable
|
||||
* to other versions.
|
||||
*
|
||||
* Modification Log:
|
||||
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
* Adapted from:
|
||||
*
|
||||
* "DHRYSTONE" Benchmark Program
|
||||
* -----------------------------
|
||||
*
|
||||
* Version: C, Version 2.1
|
||||
*
|
||||
* File: dhry_1.c (part 2 of 3)
|
||||
*
|
||||
* Date: May 25, 1988
|
||||
*
|
||||
* Author: Reinhold P. Weicker
|
||||
*
|
||||
***************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)dhry_1.c:3.4 -- 5/15/91 19:30:21";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "dhry.h"
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long Run_Index;
|
||||
|
||||
Enumeration Func_1(Capital_Letter, Capital_Letter);
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%ld|1|lps\n", Run_Index);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Global Variables: */
|
||||
|
||||
Rec_Pointer Ptr_Glob,
|
||||
Next_Ptr_Glob;
|
||||
int Int_Glob;
|
||||
Boolean Bool_Glob;
|
||||
char Ch_1_Glob,
|
||||
Ch_2_Glob;
|
||||
int Arr_1_Glob [50];
|
||||
int Arr_2_Glob [50] [50];
|
||||
|
||||
|
||||
#ifndef REG
|
||||
Boolean Reg = false;
|
||||
#define REG
|
||||
/* REG becomes defined as empty */
|
||||
/* i.e. no register variables */
|
||||
#else
|
||||
Boolean Reg = true;
|
||||
#endif
|
||||
|
||||
/* variables for time measurement: */
|
||||
|
||||
#ifdef TIMES
|
||||
struct tms time_info;
|
||||
extern int times ();
|
||||
/* see library function "times" */
|
||||
#define Too_Small_Time 120
|
||||
/* Measurements should last at least about 2 seconds */
|
||||
#endif
|
||||
#ifdef TIME
|
||||
#define Too_Small_Time 2
|
||||
/* Measurements should last at least 2 seconds */
|
||||
#endif
|
||||
|
||||
long Begin_Time,
|
||||
End_Time,
|
||||
User_Time;
|
||||
float Microseconds,
|
||||
Dhrystones_Per_Second;
|
||||
|
||||
/* end of variables for time measurement */
|
||||
|
||||
void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
|
||||
void Proc_2 (One_Fifty *Int_Par_Ref);
|
||||
void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
|
||||
void Proc_4 (void);
|
||||
void Proc_5 (void);
|
||||
|
||||
|
||||
extern Boolean Func_2(Str_30, Str_30);
|
||||
extern void Proc_6(Enumeration, Enumeration *);
|
||||
extern void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
|
||||
extern void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
/* main program, corresponds to procedures */
|
||||
/* Main and Proc_0 in the Ada version */
|
||||
{
|
||||
int duration;
|
||||
One_Fifty Int_1_Loc;
|
||||
REG One_Fifty Int_2_Loc;
|
||||
One_Fifty Int_3_Loc;
|
||||
REG char Ch_Index;
|
||||
Enumeration Enum_Loc;
|
||||
Str_30 Str_1_Loc;
|
||||
Str_30 Str_2_Loc;
|
||||
|
||||
/* Initializations */
|
||||
|
||||
Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
|
||||
Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
|
||||
|
||||
Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
|
||||
Ptr_Glob->Discr = Ident_1;
|
||||
Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
|
||||
Ptr_Glob->variant.var_1.Int_Comp = 40;
|
||||
strcpy (Ptr_Glob->variant.var_1.Str_Comp,
|
||||
"DHRYSTONE PROGRAM, SOME STRING");
|
||||
strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
|
||||
|
||||
Arr_2_Glob [8][7] = 10;
|
||||
/* Was missing in published program. Without this statement, */
|
||||
/* Arr_2_Glob [8][7] would have an undefined value. */
|
||||
/* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
|
||||
/* overflow may occur for this array element. */
|
||||
|
||||
#ifdef PRATTLE
|
||||
printf ("\n");
|
||||
printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
|
||||
printf ("\n");
|
||||
if (Reg)
|
||||
{
|
||||
printf ("Program compiled with 'register' attribute\n");
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Program compiled without 'register' attribute\n");
|
||||
printf ("\n");
|
||||
}
|
||||
printf ("Please give the number of runs through the benchmark: ");
|
||||
{
|
||||
int n;
|
||||
scanf ("%d", &n);
|
||||
Number_Of_Runs = n;
|
||||
}
|
||||
printf ("\n");
|
||||
|
||||
printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs);
|
||||
#endif /* PRATTLE */
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
Run_Index = 0;
|
||||
wake_me(duration, report);
|
||||
|
||||
/***************/
|
||||
/* Start timer */
|
||||
/***************/
|
||||
|
||||
#ifdef SELF_TIMED
|
||||
#ifdef TIMES
|
||||
times (&time_info);
|
||||
Begin_Time = (long) time_info.tms_utime;
|
||||
#endif
|
||||
#ifdef TIME
|
||||
Begin_Time = time ( (long *) 0);
|
||||
#endif
|
||||
#endif /* SELF_TIMED */
|
||||
|
||||
for (Run_Index = 1; ; ++Run_Index)
|
||||
{
|
||||
|
||||
Proc_5();
|
||||
Proc_4();
|
||||
/* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
|
||||
Int_1_Loc = 2;
|
||||
Int_2_Loc = 3;
|
||||
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
|
||||
Enum_Loc = Ident_2;
|
||||
Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
|
||||
/* Bool_Glob == 1 */
|
||||
while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
|
||||
{
|
||||
Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
|
||||
/* Int_3_Loc == 7 */
|
||||
Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
|
||||
/* Int_3_Loc == 7 */
|
||||
Int_1_Loc += 1;
|
||||
} /* while */
|
||||
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
|
||||
Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
|
||||
/* Int_Glob == 5 */
|
||||
Proc_1 (Ptr_Glob);
|
||||
for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
|
||||
/* loop body executed twice */
|
||||
{
|
||||
if (Enum_Loc == Func_1 (Ch_Index, 'C'))
|
||||
/* then, not executed */
|
||||
{
|
||||
Proc_6 (Ident_1, &Enum_Loc);
|
||||
strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
|
||||
Int_2_Loc = Run_Index;
|
||||
Int_Glob = Run_Index;
|
||||
}
|
||||
}
|
||||
/* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
|
||||
Int_2_Loc = Int_2_Loc * Int_1_Loc;
|
||||
Int_1_Loc = Int_2_Loc / Int_3_Loc;
|
||||
Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
|
||||
/* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
|
||||
Proc_2 (&Int_1_Loc);
|
||||
/* Int_1_Loc == 5 */
|
||||
|
||||
} /* loop "for Run_Index" */
|
||||
|
||||
/**************/
|
||||
/* Stop timer */
|
||||
/**************/
|
||||
#ifdef SELF_TIMED
|
||||
#ifdef TIMES
|
||||
times (&time_info);
|
||||
End_Time = (long) time_info.tms_utime;
|
||||
#endif
|
||||
#ifdef TIME
|
||||
End_Time = time ( (long *) 0);
|
||||
#endif
|
||||
#endif /* SELF_TIMED */
|
||||
|
||||
/* BYTE version never executes this stuff */
|
||||
#ifdef SELF_TIMED
|
||||
printf ("Execution ends\n");
|
||||
printf ("\n");
|
||||
printf ("Final values of the variables used in the benchmark:\n");
|
||||
printf ("\n");
|
||||
printf ("Int_Glob: %d\n", Int_Glob);
|
||||
printf (" should be: %d\n", 5);
|
||||
printf ("Bool_Glob: %d\n", Bool_Glob);
|
||||
printf (" should be: %d\n", 1);
|
||||
printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
|
||||
printf (" should be: %c\n", 'A');
|
||||
printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
|
||||
printf (" should be: %c\n", 'B');
|
||||
printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
|
||||
printf (" should be: %d\n", 7);
|
||||
printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
|
||||
printf (" should be: Number_Of_Runs + 10\n");
|
||||
printf ("Ptr_Glob->\n");
|
||||
printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
|
||||
printf (" should be: (implementation-dependent)\n");
|
||||
printf (" Discr: %d\n", Ptr_Glob->Discr);
|
||||
printf (" should be: %d\n", 0);
|
||||
printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
|
||||
printf (" should be: %d\n", 2);
|
||||
printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
|
||||
printf (" should be: %d\n", 17);
|
||||
printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
|
||||
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
|
||||
printf ("Next_Ptr_Glob->\n");
|
||||
printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
|
||||
printf (" should be: (implementation-dependent), same as above\n");
|
||||
printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
|
||||
printf (" should be: %d\n", 0);
|
||||
printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
|
||||
printf (" should be: %d\n", 1);
|
||||
printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
|
||||
printf (" should be: %d\n", 18);
|
||||
printf (" Str_Comp: %s\n",
|
||||
Next_Ptr_Glob->variant.var_1.Str_Comp);
|
||||
printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
|
||||
printf ("Int_1_Loc: %d\n", Int_1_Loc);
|
||||
printf (" should be: %d\n", 5);
|
||||
printf ("Int_2_Loc: %d\n", Int_2_Loc);
|
||||
printf (" should be: %d\n", 13);
|
||||
printf ("Int_3_Loc: %d\n", Int_3_Loc);
|
||||
printf (" should be: %d\n", 7);
|
||||
printf ("Enum_Loc: %d\n", Enum_Loc);
|
||||
printf (" should be: %d\n", 1);
|
||||
printf ("Str_1_Loc: %s\n", Str_1_Loc);
|
||||
printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
|
||||
printf ("Str_2_Loc: %s\n", Str_2_Loc);
|
||||
printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
|
||||
printf ("\n");
|
||||
|
||||
User_Time = End_Time - Begin_Time;
|
||||
|
||||
if (User_Time < Too_Small_Time)
|
||||
{
|
||||
printf ("Measured time too small to obtain meaningful results\n");
|
||||
printf ("Please increase number of runs\n");
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef TIME
|
||||
Microseconds = (float) User_Time * Mic_secs_Per_Second
|
||||
/ (float) Number_Of_Runs;
|
||||
Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time;
|
||||
#else
|
||||
Microseconds = (float) User_Time * Mic_secs_Per_Second
|
||||
/ ((float) HZ * ((float) Number_Of_Runs));
|
||||
Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs)
|
||||
/ (float) User_Time;
|
||||
#endif
|
||||
printf ("Microseconds for one run through Dhrystone: ");
|
||||
printf ("%6.1f \n", Microseconds);
|
||||
printf ("Dhrystones per Second: ");
|
||||
printf ("%6.1f \n", Dhrystones_Per_Second);
|
||||
printf ("\n");
|
||||
}
|
||||
#endif /* SELF_TIMED */
|
||||
}
|
||||
|
||||
|
||||
void Proc_1 (REG Rec_Pointer Ptr_Val_Par)
|
||||
/* executed once */
|
||||
{
|
||||
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
|
||||
/* == Ptr_Glob_Next */
|
||||
/* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
|
||||
/* corresponds to "rename" in Ada, "with" in Pascal */
|
||||
|
||||
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
|
||||
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
|
||||
Next_Record->variant.var_1.Int_Comp
|
||||
= Ptr_Val_Par->variant.var_1.Int_Comp;
|
||||
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
|
||||
Proc_3 (&Next_Record->Ptr_Comp);
|
||||
/* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
|
||||
== Ptr_Glob->Ptr_Comp */
|
||||
if (Next_Record->Discr == Ident_1)
|
||||
/* then, executed */
|
||||
{
|
||||
Next_Record->variant.var_1.Int_Comp = 6;
|
||||
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
|
||||
&Next_Record->variant.var_1.Enum_Comp);
|
||||
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
|
||||
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
|
||||
&Next_Record->variant.var_1.Int_Comp);
|
||||
}
|
||||
else /* not executed */
|
||||
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
|
||||
} /* Proc_1 */
|
||||
|
||||
|
||||
void Proc_2 (One_Fifty *Int_Par_Ref)
|
||||
/* executed once */
|
||||
/* *Int_Par_Ref == 1, becomes 4 */
|
||||
{
|
||||
One_Fifty Int_Loc;
|
||||
Enumeration Enum_Loc;
|
||||
|
||||
Enum_Loc = 0;
|
||||
|
||||
Int_Loc = *Int_Par_Ref + 10;
|
||||
do /* executed once */
|
||||
if (Ch_1_Glob == 'A')
|
||||
/* then, executed */
|
||||
{
|
||||
Int_Loc -= 1;
|
||||
*Int_Par_Ref = Int_Loc - Int_Glob;
|
||||
Enum_Loc = Ident_1;
|
||||
} /* if */
|
||||
while (Enum_Loc != Ident_1); /* true */
|
||||
} /* Proc_2 */
|
||||
|
||||
|
||||
void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
|
||||
/* executed once */
|
||||
/* Ptr_Ref_Par becomes Ptr_Glob */
|
||||
{
|
||||
if (Ptr_Glob != Null)
|
||||
/* then, executed */
|
||||
*Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
|
||||
Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
|
||||
} /* Proc_3 */
|
||||
|
||||
|
||||
void Proc_4 (void) /* without parameters */
|
||||
/* executed once */
|
||||
{
|
||||
Boolean Bool_Loc;
|
||||
|
||||
Bool_Loc = Ch_1_Glob == 'A';
|
||||
Bool_Glob = Bool_Loc | Bool_Glob;
|
||||
Ch_2_Glob = 'B';
|
||||
} /* Proc_4 */
|
||||
|
||||
void Proc_5 (void) /* without parameters */
|
||||
/*******/
|
||||
/* executed once */
|
||||
{
|
||||
Ch_1_Glob = 'A';
|
||||
Bool_Glob = false;
|
||||
} /* Proc_5 */
|
||||
|
||||
|
||||
/* Procedure for the assignment of structures, */
|
||||
/* if the C compiler doesn't support this feature */
|
||||
#ifdef NOSTRUCTASSIGN
|
||||
memcpy (d, s, l)
|
||||
register char *d;
|
||||
register char *s;
|
||||
register int l;
|
||||
{
|
||||
while (l--) *d++ = *s++;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: dhry_2.c SID: 3.4 5/15/91 19:30:22
|
||||
*
|
||||
*****************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*****************************************************************************
|
||||
* Modification Log:
|
||||
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
* Adapted from:
|
||||
*
|
||||
* "DHRYSTONE" Benchmark Program
|
||||
* -----------------------------
|
||||
*
|
||||
* **** WARNING **** See warning in n.dhry_1.c
|
||||
*
|
||||
* Version: C, Version 2.1
|
||||
*
|
||||
* File: dhry_2.c (part 3 of 3)
|
||||
*
|
||||
* Date: May 25, 1988
|
||||
*
|
||||
* Author: Reinhold P. Weicker
|
||||
*
|
||||
****************************************************************************/
|
||||
/* SCCSid is defined in dhry_1.c */
|
||||
|
||||
#include <string.h>
|
||||
#include "dhry.h"
|
||||
|
||||
#ifndef REG
|
||||
#define REG
|
||||
/* REG becomes defined as empty */
|
||||
/* i.e. no register variables */
|
||||
#endif
|
||||
|
||||
extern int Int_Glob;
|
||||
extern char Ch_1_Glob;
|
||||
|
||||
void Proc_6(Enumeration, Enumeration *);
|
||||
void Proc_7(One_Fifty, One_Fifty, One_Fifty *);
|
||||
void Proc_8(Arr_1_Dim, Arr_2_Dim, int, int);
|
||||
Enumeration Func_1(Capital_Letter, Capital_Letter);
|
||||
Boolean Func_2(Str_30, Str_30);
|
||||
Boolean Func_3(Enumeration);
|
||||
|
||||
void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
|
||||
/* executed once */
|
||||
/* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
|
||||
{
|
||||
*Enum_Ref_Par = Enum_Val_Par;
|
||||
if (! Func_3 (Enum_Val_Par))
|
||||
/* then, not executed */
|
||||
*Enum_Ref_Par = Ident_4;
|
||||
switch (Enum_Val_Par)
|
||||
{
|
||||
case Ident_1:
|
||||
*Enum_Ref_Par = Ident_1;
|
||||
break;
|
||||
case Ident_2:
|
||||
if (Int_Glob > 100)
|
||||
/* then */
|
||||
*Enum_Ref_Par = Ident_1;
|
||||
else *Enum_Ref_Par = Ident_4;
|
||||
break;
|
||||
case Ident_3: /* executed */
|
||||
*Enum_Ref_Par = Ident_2;
|
||||
break;
|
||||
case Ident_4: break;
|
||||
case Ident_5:
|
||||
*Enum_Ref_Par = Ident_3;
|
||||
break;
|
||||
} /* switch */
|
||||
} /* Proc_6 */
|
||||
|
||||
void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
|
||||
One_Fifty Int_1_Par_Val;
|
||||
One_Fifty Int_2_Par_Val;
|
||||
One_Fifty *Int_Par_Ref;
|
||||
/**********************************************/
|
||||
/* executed three times */
|
||||
/* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
|
||||
/* Int_Par_Ref becomes 7 */
|
||||
/* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
|
||||
/* Int_Par_Ref becomes 17 */
|
||||
/* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
|
||||
/* Int_Par_Ref becomes 18 */
|
||||
{
|
||||
One_Fifty Int_Loc;
|
||||
|
||||
Int_Loc = Int_1_Par_Val + 2;
|
||||
*Int_Par_Ref = Int_2_Par_Val + Int_Loc;
|
||||
} /* Proc_7 */
|
||||
|
||||
|
||||
void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
|
||||
/*********************************************************************/
|
||||
/* executed once */
|
||||
/* Int_Par_Val_1 == 3 */
|
||||
/* Int_Par_Val_2 == 7 */
|
||||
Arr_1_Dim Arr_1_Par_Ref;
|
||||
Arr_2_Dim Arr_2_Par_Ref;
|
||||
int Int_1_Par_Val;
|
||||
int Int_2_Par_Val;
|
||||
{
|
||||
REG One_Fifty Int_Index;
|
||||
REG One_Fifty Int_Loc;
|
||||
|
||||
Int_Loc = Int_1_Par_Val + 5;
|
||||
Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
|
||||
Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
|
||||
Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
|
||||
for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
|
||||
Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
|
||||
Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
|
||||
Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
|
||||
Int_Glob = 5;
|
||||
} /* Proc_8 */
|
||||
|
||||
|
||||
Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
|
||||
/*************************************************/
|
||||
/* executed three times */
|
||||
/* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
|
||||
/* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
|
||||
/* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
|
||||
{
|
||||
Capital_Letter Ch_1_Loc;
|
||||
Capital_Letter Ch_2_Loc;
|
||||
|
||||
Ch_1_Loc = Ch_1_Par_Val;
|
||||
Ch_2_Loc = Ch_1_Loc;
|
||||
if (Ch_2_Loc != Ch_2_Par_Val)
|
||||
/* then, executed */
|
||||
return (Ident_1);
|
||||
else /* not executed */
|
||||
{
|
||||
Ch_1_Glob = Ch_1_Loc;
|
||||
return (Ident_2);
|
||||
}
|
||||
} /* Func_1 */
|
||||
|
||||
|
||||
|
||||
Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
|
||||
/*************************************************/
|
||||
/* executed once */
|
||||
/* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
|
||||
/* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
|
||||
|
||||
Str_30 Str_1_Par_Ref;
|
||||
Str_30 Str_2_Par_Ref;
|
||||
{
|
||||
REG One_Thirty Int_Loc;
|
||||
Capital_Letter Ch_Loc;
|
||||
|
||||
Ch_Loc = 'A';
|
||||
Int_Loc = 2;
|
||||
while (Int_Loc <= 2) /* loop body executed once */
|
||||
if (Func_1 (Str_1_Par_Ref[Int_Loc],
|
||||
Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
|
||||
/* then, executed */
|
||||
{
|
||||
Ch_Loc = 'A';
|
||||
Int_Loc += 1;
|
||||
} /* if, while */
|
||||
if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
|
||||
/* then, not executed */
|
||||
Int_Loc = 7;
|
||||
if (Ch_Loc == 'R')
|
||||
/* then, not executed */
|
||||
return (true);
|
||||
else /* executed */
|
||||
{
|
||||
if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
|
||||
/* then, not executed */
|
||||
{
|
||||
Int_Loc += 7;
|
||||
Int_Glob = Int_Loc;
|
||||
return (true);
|
||||
}
|
||||
else /* executed */
|
||||
return (false);
|
||||
} /* if Ch_Loc */
|
||||
} /* Func_2 */
|
||||
|
||||
|
||||
Boolean Func_3 (Enum_Par_Val)
|
||||
/***************************/
|
||||
/* executed once */
|
||||
/* Enum_Par_Val == Ident_3 */
|
||||
Enumeration Enum_Par_Val;
|
||||
{
|
||||
Enumeration Enum_Loc;
|
||||
|
||||
Enum_Loc = Enum_Par_Val;
|
||||
if (Enum_Loc == Ident_3)
|
||||
/* then, executed */
|
||||
return (true);
|
||||
else /* not executed */
|
||||
return (false);
|
||||
} /* Func_3 */
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: dummy.c SID: 3.3 5/15/91 19:30:19
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Hacked up C program for use in the standard shell.? scripts of
|
||||
* the multiuser test. This is based upon makework.c, and is typically
|
||||
* edited using edscript.2 before compilation.
|
||||
*
|
||||
* $Header: dummy.c,v 3.4 87/06/23 15:54:53 kjmcdonell Beta $
|
||||
*/
|
||||
char SCCSid[] = "@(#) @(#)dummy.c:3.3 -- 5/15/91 19:30:19";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define DEF_RATE 5.0
|
||||
#define GRANULE 5
|
||||
#define CHUNK 60
|
||||
#define MAXCHILD 12
|
||||
#define MAXWORK 10
|
||||
|
||||
float thres;
|
||||
float est_rate = DEF_RATE;
|
||||
int nusers; /* number of concurrent users to be simulated by
|
||||
* this process */
|
||||
int firstuser; /* ordinal identification of first user for this
|
||||
* process */
|
||||
int nwork = 0; /* number of job streams */
|
||||
int exit_status = 0; /* returned to parent */
|
||||
int sigpipe; /* pipe write error flag */
|
||||
|
||||
struct st_work {
|
||||
char *cmd; /* name of command to run */
|
||||
char **av; /* arguments to command */
|
||||
char *input; /* standard input buffer */
|
||||
int inpsize; /* size of standard input buffer */
|
||||
} work[MAXWORK];
|
||||
|
||||
struct {
|
||||
int xmit; /* # characters sent */
|
||||
char *bp; /* std input buffer pointer */
|
||||
int blen; /* std input buffer length */
|
||||
int fd; /* stdin to command */
|
||||
int pid; /* child PID */
|
||||
char *line; /* start of input line */
|
||||
int firstjob; /* inital piece of work */
|
||||
int thisjob; /* current piece of work */
|
||||
} child[MAXCHILD], *cp;
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
int l;
|
||||
int fcopy = 0; /* fd for copy output */
|
||||
int master = 1; /* the REAL master, == 0 for clones */
|
||||
int nchild; /* no. of children for a clone to run */
|
||||
int done; /* count of children finished */
|
||||
int output; /* aggregate output char count for all
|
||||
children */
|
||||
int c;
|
||||
int thiswork = 0; /* next job stream to allocate */
|
||||
int nch; /* # characters to write */
|
||||
int written; /* # characters actully written */
|
||||
char logname[15]; /* name of the log file(s) */
|
||||
void onalarm(void);
|
||||
void pipeerr(void);
|
||||
void wrapup(void);
|
||||
void grunt(void);
|
||||
char *malloc();
|
||||
int pvec[2]; /* for pipes */
|
||||
char *p;
|
||||
char *prog; /* my name */
|
||||
|
||||
#if ! debug
|
||||
freopen("masterlog.00", "a", stderr);
|
||||
#endif
|
||||
fprintf(stderr, "*** New Run *** ");
|
||||
prog = argv[0];
|
||||
while (argc > 1 && argv[1][0] == '-') {
|
||||
p = &argv[1][1];
|
||||
argc--;
|
||||
argv++;
|
||||
while (*p) {
|
||||
switch (*p) {
|
||||
case 'r':
|
||||
/* code DELETED here */
|
||||
argc--;
|
||||
argv++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
/* code DELETED here */
|
||||
lseek(fcopy, 0L, 2); /* append at end of file */
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
|
||||
exit(4);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s: missing nusers\n", prog);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
nusers = atoi(argv[1]);
|
||||
if (nusers < 1) {
|
||||
fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
|
||||
exit(4);
|
||||
}
|
||||
fprintf(stderr, "%d Users\n", nusers);
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* build job streams */
|
||||
getwork();
|
||||
#if debug
|
||||
dumpwork();
|
||||
#endif
|
||||
|
||||
/* clone copies of myself to run up to MAXCHILD jobs each */
|
||||
firstuser = MAXCHILD;
|
||||
fprintf(stderr, "master pid %d\n", getpid());
|
||||
fflush(stderr);
|
||||
while (nusers > MAXCHILD) {
|
||||
fflush(stderr);
|
||||
if (nusers >= 2*MAXCHILD)
|
||||
/* the next clone must run MAXCHILD jobs */
|
||||
nchild = MAXCHILD;
|
||||
else
|
||||
/* the next clone must run the leftover jobs */
|
||||
nchild = nusers - MAXCHILD;
|
||||
if ((l = fork()) == -1) {
|
||||
/* fork failed */
|
||||
fatal("** clone fork failed **\n");
|
||||
goto bepatient;
|
||||
} else if (l > 0) {
|
||||
fprintf(stderr, "master clone pid %d\n", l);
|
||||
/* I am the master with nchild fewer jobs to run */
|
||||
nusers -= nchild;
|
||||
firstuser += MAXCHILD;
|
||||
continue;
|
||||
} else {
|
||||
/* I am a clone, run MAXCHILD jobs */
|
||||
#if ! debug
|
||||
sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
|
||||
freopen(logname, "w", stderr);
|
||||
#endif
|
||||
master = 0;
|
||||
nusers = nchild;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (master)
|
||||
firstuser = 0;
|
||||
|
||||
close(0);
|
||||
|
||||
/* code DELETED here */
|
||||
|
||||
fflush(stderr);
|
||||
|
||||
srand(time(0));
|
||||
thres = 0;
|
||||
done = output = 0;
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (child[i].blen == 0)
|
||||
done++;
|
||||
else
|
||||
thres += est_rate * GRANULE;
|
||||
}
|
||||
est_rate = thres;
|
||||
|
||||
signal(SIGALRM, onalarm);
|
||||
signal(SIGPIPE, pipeerr);
|
||||
alarm(GRANULE);
|
||||
while (done < nusers) {
|
||||
for (i = 0; i < nusers; i++) {
|
||||
cp = &child[i];
|
||||
if (cp->xmit >= cp->blen) continue;
|
||||
l = rand() % CHUNK + 1; /* 1-CHUNK chars */
|
||||
if (l == 0) continue;
|
||||
if (cp->xmit + l > cp->blen)
|
||||
l = cp->blen - cp->xmit;
|
||||
p = cp->bp;
|
||||
cp->bp += l;
|
||||
cp->xmit += l;
|
||||
#if debug
|
||||
fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
|
||||
#endif
|
||||
while (p < cp->bp) {
|
||||
if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
|
||||
/* write it out */
|
||||
nch = p - cp->line + 1;
|
||||
if ((written = write(cp->fd, cp->line, nch)) != nch) {
|
||||
|
||||
/* code DELETED here */
|
||||
|
||||
}
|
||||
if (fcopy)
|
||||
write(fcopy, cp->line, p - cp->line + 1);
|
||||
#if debug
|
||||
fprintf(stderr, "child %d gets \"", i);
|
||||
{
|
||||
char *q = cp->line;
|
||||
while (q <= p) {
|
||||
if (*q >= ' ' && *q <= '~')
|
||||
fputc(*q, stderr);
|
||||
else
|
||||
fprintf(stderr, "\\%03o", *q);
|
||||
q++;
|
||||
}
|
||||
}
|
||||
fputc('"', stderr);
|
||||
#endif
|
||||
cp->line = &p[1];
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (cp->xmit >= cp->blen) {
|
||||
done++;
|
||||
close(cp->fd);
|
||||
#if debug
|
||||
fprintf(stderr, "child %d, close std input\n", i);
|
||||
#endif
|
||||
}
|
||||
output += l;
|
||||
}
|
||||
while (output > thres) {
|
||||
pause();
|
||||
#if debug
|
||||
fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bepatient:
|
||||
alarm(0);
|
||||
/****
|
||||
* If everything is going OK, we should simply be able to keep
|
||||
* looping unitil 'wait' fails, however some descendent process may
|
||||
* be in a state from which it can never exit, and so a timeout
|
||||
* is used.
|
||||
* 5 minutes should be ample, since the time to run all jobs is of
|
||||
* the order of 5-10 minutes, however some machines are painfully slow,
|
||||
* so the timeout has been set at 20 minutes (1200 seconds).
|
||||
****/
|
||||
|
||||
/* code DELETED here */
|
||||
|
||||
}
|
||||
|
||||
onalarm()
|
||||
{
|
||||
thres += est_rate;
|
||||
signal(SIGALRM, onalarm);
|
||||
alarm(GRANULE);
|
||||
}
|
||||
|
||||
grunt()
|
||||
{
|
||||
/* timeout after label "bepatient" in main */
|
||||
exit_status = 4;
|
||||
wrapup();
|
||||
}
|
||||
|
||||
pipeerr()
|
||||
{
|
||||
sigpipe++;
|
||||
}
|
||||
|
||||
wrapup()
|
||||
{
|
||||
/* DUMMY, real code dropped */
|
||||
}
|
||||
|
||||
getwork()
|
||||
{
|
||||
|
||||
/* DUMMY, real code dropped */
|
||||
gets();
|
||||
strncpy();
|
||||
malloc(); realloc();
|
||||
open(); close();
|
||||
}
|
||||
|
||||
fatal(s)
|
||||
char *s;
|
||||
{
|
||||
int i;
|
||||
fprintf(stderr, s);
|
||||
fflush(stderr);
|
||||
perror("Reason?");
|
||||
for (i = 0; i < nusers; i++) {
|
||||
if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1)
|
||||
fprintf(stderr, "pid %d killed off\n", child[i].pid);
|
||||
}
|
||||
fflush(stderr);
|
||||
exit_status = 4;
|
||||
return;
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: execl.c SID: 3.3 5/15/91 19:30:19
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: execl.c,v 3.5 87/06/22 15:37:08 kjmcdonell Beta $
|
||||
* August 28, 1990 - Modified timing routines
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
/*
|
||||
* Execing
|
||||
*
|
||||
*/
|
||||
char SCCSid[] = "@(#) @(#)execl.c:3.3 -- 5/15/91 19:30:19";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
char bss[8*1024]; /* something worthwhile */
|
||||
|
||||
#define main dummy
|
||||
|
||||
#include "big.c" /* some real code */
|
||||
|
||||
#undef main
|
||||
|
||||
int main(int argc, char *argv[]) /* the real program */
|
||||
{
|
||||
unsigned long iter = 0;
|
||||
char *ptr;
|
||||
char *fullpath;
|
||||
int duration;
|
||||
char count_str[12], start_str[24], path_str[256], *dur_str;
|
||||
time_t start_time, this_time;
|
||||
|
||||
#ifdef DEBUG
|
||||
int count;
|
||||
for(count = 0; count < argc; ++ count)
|
||||
printf("%s ",argv[count]);
|
||||
printf("\n");
|
||||
#endif
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
if (duration > 0)
|
||||
/* the first invocation */
|
||||
{
|
||||
dur_str = argv[1];
|
||||
if((ptr = getenv("UB_BINDIR")) != NULL)
|
||||
sprintf(path_str,"%s/execl",ptr);
|
||||
fullpath=path_str;
|
||||
time(&start_time);
|
||||
}
|
||||
else /* one of those execl'd invocations */
|
||||
{
|
||||
/* real duration follow the phoney null duration */
|
||||
duration = atoi(argv[2]);
|
||||
dur_str = argv[2];
|
||||
iter = (unsigned long)atoi(argv[3]); /* where are we now ? */
|
||||
sscanf(argv[4], "%lu", (unsigned long *) &start_time);
|
||||
fullpath = argv[0];
|
||||
}
|
||||
|
||||
sprintf(count_str, "%lu", ++iter); /* increment the execl counter */
|
||||
sprintf(start_str, "%lu", (unsigned long) start_time);
|
||||
time(&this_time);
|
||||
if (this_time - start_time >= duration) { /* time has run out */
|
||||
fprintf(stderr, "COUNT|%lu|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
execl(fullpath, fullpath, "0", dur_str, count_str, start_str, (void *) 0);
|
||||
fprintf(stderr, "Exec failed at iteration %lu\n", iter);
|
||||
perror("Reason");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,471 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: fstime.c SID: 3.5 5/15/91 19:30:19
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: fstime.c,v 3.4 87/06/22 14:23:05 kjmcdonell Beta $
|
||||
* 10/19/89 - rewrote timing calcs and added clock check (Ben Smith)
|
||||
* 10/26/90 - simplify timing, change defaults (Tom Yager)
|
||||
* 11/16/90 - added better error handling and changed output format (Ben Smith)
|
||||
* 11/17/90 - changed the whole thing around (Ben Smith)
|
||||
* 2/22/91 - change a few style elements and improved error handling (Ben Smith)
|
||||
* 4/17/91 - incorporated suggestions from Seckin Unlu (seckin@sumac.intel.com)
|
||||
* 4/17/91 - limited size of file, will rewind when reaches end of file
|
||||
* 7/95 - fixed mishandling of read() and write() return codes
|
||||
* Carl Emilio Prelz <fluido@telepac.pt>
|
||||
* 12/95 - Massive changes. Made sleep time proportional increase with run
|
||||
* time; added fsbuffer and fsdisk variants; added partial counting
|
||||
* of partial reads/writes (was *full* credit); added dual syncs.
|
||||
* David C Niemi <niemi@tux.org>
|
||||
* 10/22/97 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
* 9/24/07 - Separate out the read and write tests;
|
||||
* output the actual time used in the results.
|
||||
* Ian Smith <johantheghost at yahoo period com>
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)fstime.c:3.5 -- 5/15/91 19:30:19";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define SECONDS 10
|
||||
|
||||
#define MAX_BUFSIZE 8192
|
||||
|
||||
/* This must be set to the smallest BUFSIZE or 1024, whichever is smaller */
|
||||
#define COUNTSIZE 256
|
||||
#define HALFCOUNT (COUNTSIZE/2) /* Half of COUNTSIZE */
|
||||
|
||||
#define FNAME0 "dummy0"
|
||||
#define FNAME1 "dummy1"
|
||||
|
||||
#ifndef MINIX
|
||||
extern void sync(void);
|
||||
#else
|
||||
extern int sync(void);
|
||||
#endif
|
||||
|
||||
int w_test(int timeSecs);
|
||||
int r_test(int timeSecs);
|
||||
int c_test(int timeSecs);
|
||||
|
||||
long read_score = 1, write_score = 1, copy_score = 1;
|
||||
|
||||
/****************** GLOBALS ***************************/
|
||||
|
||||
/* The buffer size for the tests. */
|
||||
int bufsize = 1024;
|
||||
|
||||
/*
|
||||
* The max number of 1024-byte blocks in the file.
|
||||
* Don't limit it much, so that memory buffering
|
||||
* can be overcome.
|
||||
*/
|
||||
int max_blocks = 2000;
|
||||
|
||||
/* The max number of BUFSIZE blocks in the file. */
|
||||
int max_buffs = 2000;
|
||||
|
||||
/* Countable units per 1024 bytes */
|
||||
int count_per_k;
|
||||
|
||||
/* Countable units per bufsize */
|
||||
int count_per_buf;
|
||||
|
||||
/* The actual buffer. */
|
||||
/* char *buf = 0; */
|
||||
/* Let's carry on using a static buffer for this, like older versions
|
||||
* of the code did. It turns out that if you use a malloc buffer,
|
||||
* it goes 50% slower on reads, when using a 4k buffer -- at least on
|
||||
* my OpenSUSE 10.2 system.
|
||||
* What up wit dat?
|
||||
*/
|
||||
char buf[MAX_BUFSIZE];
|
||||
|
||||
int f;
|
||||
int g;
|
||||
int i;
|
||||
void stop_count(int);
|
||||
void clean_up(int);
|
||||
int sigalarm = 0;
|
||||
|
||||
/******************** MAIN ****************************/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* The number of seconds to run for. */
|
||||
int seconds = SECONDS;
|
||||
|
||||
/* The type of test to run. */
|
||||
char test = 'c';
|
||||
|
||||
int status;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch (argv[i][1]) {
|
||||
case 'c':
|
||||
case 'r':
|
||||
case 'w':
|
||||
test = argv[i][1];
|
||||
break;
|
||||
case 'b':
|
||||
bufsize = atoi(argv[++i]);
|
||||
break;
|
||||
case 'm':
|
||||
max_blocks = atoi(argv[++i]);
|
||||
break;
|
||||
case 't':
|
||||
seconds = atoi(argv[++i]);
|
||||
break;
|
||||
case 'd':
|
||||
if (chdir(argv[++i]) < 0) {
|
||||
perror("fstime: chdir");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Usage: fstime [-c|-r|-w] [-b <bufsize>] [-m <max_blocks>] [-t <seconds>]\n");
|
||||
exit(2);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Usage: fstime [-c|-r|-w] [-b <bufsize>] [-m <max_blocks>] [-t <seconds>]\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (bufsize < COUNTSIZE || bufsize > MAX_BUFSIZE) {
|
||||
fprintf(stderr, "fstime: buffer size must be in range %d-%d\n",
|
||||
COUNTSIZE, 1024*1024);
|
||||
exit(3);
|
||||
}
|
||||
if (max_blocks < 1 || max_blocks > 1024*1024) {
|
||||
fprintf(stderr, "fstime: max blocks must be in range %d-%d\n",
|
||||
1, 1024*1024);
|
||||
exit(3);
|
||||
}
|
||||
if (seconds < 1 || seconds > 3600) {
|
||||
fprintf(stderr, "fstime: time must be in range %d-%d seconds\n",
|
||||
1, 3600);
|
||||
exit(3);
|
||||
}
|
||||
|
||||
max_buffs = max_blocks * 1024 / bufsize;
|
||||
count_per_k = 1024 / COUNTSIZE;
|
||||
count_per_buf = bufsize / COUNTSIZE;
|
||||
|
||||
/*
|
||||
if ((buf = malloc(bufsize)) == 0) {
|
||||
fprintf(stderr, "fstime: failed to malloc %d bytes\n", bufsize);
|
||||
exit(4);
|
||||
}
|
||||
*/
|
||||
|
||||
if((f = creat(FNAME0, 0600)) == -1) {
|
||||
perror("fstime: creat");
|
||||
exit(1);
|
||||
}
|
||||
close(f);
|
||||
|
||||
if((g = creat(FNAME1, 0600)) == -1) {
|
||||
perror("fstime: creat");
|
||||
exit(1);
|
||||
}
|
||||
close(g);
|
||||
|
||||
if( (f = open(FNAME0, 2)) == -1) {
|
||||
perror("fstime: open");
|
||||
exit(1);
|
||||
}
|
||||
if( ( g = open(FNAME1, 2)) == -1 ) {
|
||||
perror("fstime: open");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* fill buffer */
|
||||
for (i=0; i < bufsize; ++i)
|
||||
buf[i] = i & 0xff;
|
||||
|
||||
signal(SIGKILL,clean_up);
|
||||
|
||||
/*
|
||||
* Run the selected test.
|
||||
* When I got here, this program ran full 30-second tests for
|
||||
* write, read, and copy, outputting the results for each. BUT
|
||||
* only the copy results are actually used in the benchmark index.
|
||||
* With multiple iterations and three sets of FS tests, that amounted
|
||||
* to about 10 minutes of wasted time per run.
|
||||
*
|
||||
* So, I've made the test selectable. Except that the read and write
|
||||
* passes are used to create the test file and calibrate the rates used
|
||||
* to tweak the results of the copy test. So, for copy tests, we do
|
||||
* a few seconds of write and read to prime the pump.
|
||||
*
|
||||
* Note that this will also pull the file into the FS cache on any
|
||||
* modern system prior to the copy test. Whether this is good or
|
||||
* bad is a matter of perspective, but it's how it was when I got
|
||||
* here.
|
||||
*
|
||||
* Ian Smith <johantheghost at yahoo period com> 21 Sep 2007
|
||||
*/
|
||||
switch (test) {
|
||||
case 'w':
|
||||
status = w_test(seconds);
|
||||
break;
|
||||
case 'r':
|
||||
w_test(2);
|
||||
status = r_test(seconds);
|
||||
break;
|
||||
case 'c':
|
||||
w_test(2);
|
||||
r_test(2);
|
||||
status = c_test(seconds);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "fstime: unknown test \'%c\'\n", test);
|
||||
exit(6);
|
||||
}
|
||||
if (status) {
|
||||
clean_up(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
clean_up(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static double getFloatTime(void)
|
||||
{
|
||||
struct timeval t;
|
||||
|
||||
gettimeofday(&t, 0);
|
||||
return (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run the write test for the time given in seconds.
|
||||
*/
|
||||
int w_test(int timeSecs)
|
||||
{
|
||||
unsigned long counted = 0L;
|
||||
unsigned long tmp;
|
||||
long f_blocks;
|
||||
double start, end;
|
||||
extern int sigalarm;
|
||||
|
||||
/* Sync and let it settle */
|
||||
sync();
|
||||
sleep(2);
|
||||
sync();
|
||||
sleep(2);
|
||||
|
||||
/* Set an alarm. */
|
||||
sigalarm = 0;
|
||||
signal(SIGALRM, stop_count);
|
||||
alarm(timeSecs);
|
||||
|
||||
start = getFloatTime();
|
||||
|
||||
while (!sigalarm) {
|
||||
for(f_blocks=0; f_blocks < max_buffs; ++f_blocks) {
|
||||
if ((tmp=write(f, buf, bufsize)) != bufsize) {
|
||||
if (errno != EINTR) {
|
||||
perror("fstime: write");
|
||||
return(-1);
|
||||
}
|
||||
stop_count(0);
|
||||
counted += ((tmp+HALFCOUNT)/COUNTSIZE);
|
||||
} else
|
||||
counted += count_per_buf;
|
||||
}
|
||||
lseek(f, 0L, 0); /* rewind */
|
||||
}
|
||||
|
||||
/* stop clock */
|
||||
end = getFloatTime();
|
||||
write_score = (long) ((double) counted / ((end - start) * count_per_k));
|
||||
printf("Write done: %ld in %.4f, score %ld\n",
|
||||
counted, end - start, write_score);
|
||||
|
||||
/*
|
||||
* Output the test results. Use the true time.
|
||||
*/
|
||||
fprintf(stderr, "COUNT|%ld|0|KBps\n", write_score);
|
||||
fprintf(stderr, "TIME|%.1f\n", end - start);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the read test for the time given in seconds.
|
||||
*/
|
||||
int r_test(int timeSecs)
|
||||
{
|
||||
unsigned long counted = 0L;
|
||||
unsigned long tmp;
|
||||
double start, end;
|
||||
extern int sigalarm;
|
||||
extern int errno;
|
||||
|
||||
/* Sync and let it settle */
|
||||
sync();
|
||||
sleep(2);
|
||||
sync();
|
||||
sleep(2);
|
||||
|
||||
/* rewind */
|
||||
errno = 0;
|
||||
lseek(f, 0L, 0);
|
||||
|
||||
/* Set an alarm. */
|
||||
sigalarm = 0;
|
||||
signal(SIGALRM, stop_count);
|
||||
alarm(timeSecs);
|
||||
|
||||
start = getFloatTime();
|
||||
|
||||
while (!sigalarm) {
|
||||
/* read while checking for an error */
|
||||
if ((tmp=read(f, buf, bufsize)) != bufsize) {
|
||||
switch(errno) {
|
||||
case 0:
|
||||
case EINVAL:
|
||||
lseek(f, 0L, 0); /* rewind at end of file */
|
||||
counted += (tmp+HALFCOUNT)/COUNTSIZE;
|
||||
continue;
|
||||
case EINTR:
|
||||
stop_count(0);
|
||||
counted += (tmp+HALFCOUNT)/COUNTSIZE;
|
||||
break;
|
||||
default:
|
||||
perror("fstime: read");
|
||||
return(-1);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
counted += count_per_buf;
|
||||
}
|
||||
|
||||
/* stop clock */
|
||||
end = getFloatTime();
|
||||
read_score = (long) ((double) counted / ((end - start) * count_per_k));
|
||||
printf("Read done: %ld in %.4f, score %ld\n",
|
||||
counted, end - start, read_score);
|
||||
|
||||
/*
|
||||
* Output the test results. Use the true time.
|
||||
*/
|
||||
fprintf(stderr, "COUNT|%ld|0|KBps\n", read_score);
|
||||
fprintf(stderr, "TIME|%.1f\n", end - start);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run the copy test for the time given in seconds.
|
||||
*/
|
||||
int c_test(int timeSecs)
|
||||
{
|
||||
unsigned long counted = 0L;
|
||||
unsigned long tmp;
|
||||
double start, end;
|
||||
extern int sigalarm;
|
||||
|
||||
sync();
|
||||
sleep(2);
|
||||
sync();
|
||||
sleep(1);
|
||||
|
||||
/* rewind */
|
||||
errno = 0;
|
||||
lseek(f, 0L, 0);
|
||||
|
||||
/* Set an alarm. */
|
||||
sigalarm = 0;
|
||||
signal(SIGALRM, stop_count);
|
||||
alarm(timeSecs);
|
||||
|
||||
start = getFloatTime();
|
||||
|
||||
while (!sigalarm) {
|
||||
if ((tmp=read(f, buf, bufsize)) != bufsize) {
|
||||
switch(errno) {
|
||||
case 0:
|
||||
case EINVAL:
|
||||
lseek(f, 0L, 0); /* rewind at end of file */
|
||||
lseek(g, 0L, 0); /* rewind the output too */
|
||||
continue;
|
||||
case EINTR:
|
||||
/* part credit for leftover bytes read */
|
||||
counted += ( (tmp * write_score) /
|
||||
(read_score + write_score)
|
||||
+ HALFCOUNT) / COUNTSIZE;
|
||||
stop_count(0);
|
||||
break;
|
||||
default:
|
||||
perror("fstime: copy read");
|
||||
return(-1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((tmp=write(g, buf, bufsize)) != bufsize) {
|
||||
if (errno != EINTR) {
|
||||
perror("fstime: copy write");
|
||||
return(-1);
|
||||
}
|
||||
counted += (
|
||||
/* Full credit for part of buffer written */
|
||||
tmp +
|
||||
|
||||
/* Plus part credit having read full buffer */
|
||||
( ((bufsize - tmp) * write_score) /
|
||||
(read_score + write_score) )
|
||||
+ HALFCOUNT) / COUNTSIZE;
|
||||
stop_count(0);
|
||||
} else
|
||||
counted += count_per_buf;
|
||||
}
|
||||
}
|
||||
|
||||
/* stop clock */
|
||||
end = getFloatTime();
|
||||
copy_score = (long) ((double) counted / ((end - start) * count_per_k));
|
||||
printf("Copy done: %ld in %.4f, score %ld\n",
|
||||
counted, end - start, copy_score);
|
||||
|
||||
/*
|
||||
* Output the test results. Use the true time.
|
||||
*/
|
||||
fprintf(stderr, "COUNT|%ld|0|KBps\n", copy_score);
|
||||
fprintf(stderr, "TIME|%.1f\n", end - start);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void stop_count(int sig)
|
||||
{
|
||||
extern int sigalarm;
|
||||
sigalarm = 1;
|
||||
}
|
||||
|
||||
void clean_up(int sig)
|
||||
{
|
||||
unlink(FNAME0);
|
||||
unlink(FNAME1);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: hanoi.c SID: 3.3 5/15/91 19:30:20
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: hanoi.c,v 3.5 87/08/06 08:11:14 kenj Exp $
|
||||
* August 28, 1990 - Modified timing routines (ty)
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)hanoi.c:3.3 -- 5/15/91 19:30:20";
|
||||
|
||||
#define other(i,j) (6-(i+j))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "timeit.c"
|
||||
|
||||
void mov(int n, int f, int t);
|
||||
|
||||
unsigned long iter = 0;
|
||||
int num[4];
|
||||
long cnt;
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%ld|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int disk=10, /* default number of disks */
|
||||
duration;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,"Usage: %s duration [disks]\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
duration = atoi(argv[1]);
|
||||
if(argc > 2) disk = atoi(argv[2]);
|
||||
num[1] = disk;
|
||||
|
||||
wake_me(duration, report);
|
||||
|
||||
while(1) {
|
||||
mov(disk,1,3);
|
||||
iter++;
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void mov(int n, int f, int t)
|
||||
{
|
||||
int o;
|
||||
if(n == 1) {
|
||||
num[f]--;
|
||||
num[t]++;
|
||||
return;
|
||||
}
|
||||
o = other(f,t);
|
||||
mov(n-1,f,o);
|
||||
mov(1,f,t);
|
||||
mov(n-1,o,t);
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 1
|
||||
* Module: looper.c SID: 1.4 5/15/91 19:30:22
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith or Tom Yager at BYTE Magazine
|
||||
* ben@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
*
|
||||
* February 25, 1991 -- created (Ben S.)
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)looper.c:1.4 -- 5/15/91 19:30:22";
|
||||
/*
|
||||
* Shell Process creation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long iter;
|
||||
char *cmd_argv[28];
|
||||
int cmd_argc;
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%lu|60|lpm\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int slave, count, duration;
|
||||
int status;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr,"Usage: %s duration command [args..]\n", argv[0]);
|
||||
fprintf(stderr," duration in seconds\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if((duration = atoi(argv[1])) < 1)
|
||||
{
|
||||
fprintf(stderr,"Usage: %s duration command [arg..]\n", argv[0]);
|
||||
fprintf(stderr," duration in seconds\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get command */
|
||||
cmd_argc=argc-2;
|
||||
for( count=2;count < argc; ++count)
|
||||
cmd_argv[count-2]=argv[count];
|
||||
#ifdef DEBUG
|
||||
printf("<<%s>>",cmd_argv[0]);
|
||||
for(count=1;count < cmd_argc; ++count)
|
||||
printf(" <%s>", cmd_argv[count]);
|
||||
putchar('\n');
|
||||
exit(0);
|
||||
#endif
|
||||
|
||||
iter = 0;
|
||||
wake_me(duration, report);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((slave = fork()) == 0)
|
||||
{ /* execute command */
|
||||
execvp(cmd_argv[0],cmd_argv);
|
||||
exit(99);
|
||||
}
|
||||
else if (slave < 0)
|
||||
{
|
||||
/* woops ... */
|
||||
fprintf(stderr,"Fork failed at iteration %lu\n", iter);
|
||||
perror("Reason");
|
||||
exit(2);
|
||||
}
|
||||
else
|
||||
/* master */
|
||||
wait(&status);
|
||||
if (status == 99 << 8)
|
||||
{
|
||||
fprintf(stderr, "Command \"%s\" didn't exec\n", cmd_argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
else if (status != 0)
|
||||
{
|
||||
fprintf(stderr,"Bad wait status: 0x%x\n", status);
|
||||
exit(2);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: pipe.c SID: 3.3 5/15/91 19:30:20
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: pipe.c,v 3.5 87/06/22 14:32:36 kjmcdonell Beta $
|
||||
* August 29, 1990 - modified timing routines (ty)
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)pipe.c:3.3 -- 5/15/91 19:30:20";
|
||||
/*
|
||||
* pipe -- test single process pipe throughput (no context switching)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long iter;
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%ld|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char buf[512];
|
||||
int pvec[2], duration;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr,"Usage: %s duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
|
||||
pipe(pvec);
|
||||
|
||||
wake_me(duration, report);
|
||||
iter = 0;
|
||||
|
||||
while (1) {
|
||||
if (write(pvec[1], buf, sizeof(buf)) != sizeof(buf)) {
|
||||
if ((errno != EINTR) && (errno != 0))
|
||||
fprintf(stderr,"write failed, error %d\n", errno);
|
||||
}
|
||||
if (read(pvec[0], buf, sizeof(buf)) != sizeof(buf)) {
|
||||
if ((errno != EINTR) && (errno != 0))
|
||||
fprintf(stderr,"read failed, error %d\n", errno);
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: spawn.c SID: 3.3 5/15/91 19:30:20
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yagerat BYTE Magazine
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: spawn.c,v 3.4 87/06/22 14:32:48 kjmcdonell Beta $
|
||||
* August 29, 1990 - Modified timing routines (ty)
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)spawn.c:3.3 -- 5/15/91 19:30:20";
|
||||
/*
|
||||
* Process creation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long iter;
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%lu|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int slave, duration;
|
||||
int status;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr,"Usage: %s duration \n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
|
||||
iter = 0;
|
||||
wake_me(duration, report);
|
||||
|
||||
while (1) {
|
||||
if ((slave = fork()) == 0) {
|
||||
/* slave .. boring */
|
||||
#if debug
|
||||
printf("fork OK\n");
|
||||
#endif
|
||||
/* kill it right away */
|
||||
exit(0);
|
||||
} else if (slave < 0) {
|
||||
/* woops ... */
|
||||
fprintf(stderr,"Fork failed at iteration %lu\n", iter);
|
||||
perror("Reason");
|
||||
exit(2);
|
||||
} else
|
||||
/* master */
|
||||
wait(&status);
|
||||
if (status != 0) {
|
||||
fprintf(stderr,"Bad wait status: 0x%x\n", status);
|
||||
exit(2);
|
||||
}
|
||||
iter++;
|
||||
#if debug
|
||||
printf("Child %d done.\n", slave);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: syscall.c SID: 3.3 5/15/91 19:30:21
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager at BYTE Magazine
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: syscall.c,v 3.4 87/06/22 14:32:54 kjmcdonell Beta $
|
||||
* August 29, 1990 - Modified timing routines
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
/*
|
||||
* syscall -- sit in a loop calling the system
|
||||
*
|
||||
*/
|
||||
char SCCSid[] = "@(#) @(#)syscall.c:3.3 -- 5/15/91 19:30:21";
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include "timeit.c"
|
||||
|
||||
unsigned long iter;
|
||||
|
||||
void report(int sig)
|
||||
{
|
||||
fprintf(stderr,"COUNT|%ld|1|lps\n", iter);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *test;
|
||||
int duration;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,"Usage: %s duration [ test ]\n", argv[0]);
|
||||
fprintf(stderr,"test is one of:\n");
|
||||
fprintf(stderr," \"mix\" (default), \"close\", \"getpid\", \"exec\"\n");
|
||||
exit(1);
|
||||
}
|
||||
if (argc > 2)
|
||||
test = argv[2];
|
||||
else
|
||||
test = "mix";
|
||||
|
||||
duration = atoi(argv[1]);
|
||||
|
||||
iter = 0;
|
||||
wake_me(duration, report);
|
||||
|
||||
switch (test[0]) {
|
||||
case 'm':
|
||||
while (1) {
|
||||
close(dup(0));
|
||||
getpid();
|
||||
getuid();
|
||||
umask(022);
|
||||
iter++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
case 'c':
|
||||
while (1) {
|
||||
close(dup(0));
|
||||
iter++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
case 'g':
|
||||
while (1) {
|
||||
getpid();
|
||||
iter++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
case 'e':
|
||||
while (1) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr,"%s: fork failed\n", argv[0]);
|
||||
exit(1);
|
||||
} else if (pid == 0) {
|
||||
execl("/bin/true", (char *) 0);
|
||||
fprintf(stderr,"%s: exec /bin/true failed\n", argv[0]);
|
||||
exit(1);
|
||||
} else {
|
||||
if (waitpid(pid, NULL, 0) < 0) {
|
||||
fprintf(stderr,"%s: waitpid failed\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
exit(9);
|
||||
}
|
||||
|
||||
@@ -1,573 +0,0 @@
|
||||
/* Programme to test how long it takes to select(2), poll(2) and poll2(2) a
|
||||
large number of file descriptors.
|
||||
|
||||
Copyright 1997 Richard Gooch rgooch@atnf.csiro.au
|
||||
Distributed under the GNU General Public License.
|
||||
|
||||
To compile this programme, use gcc -O2 -o time-polling time-polling.c
|
||||
|
||||
Extra compile flags:
|
||||
|
||||
Add -DHAS_SELECT if your operating system has the select(2) system call
|
||||
Add -DHAS_POLL if your operating system has the poll(2) system call
|
||||
Add -DHAS_POLL2 if your operating system has the poll2(2) system call
|
||||
|
||||
Usage: time-polling [num_iter] [num_to_test] [num_active] [-v]
|
||||
|
||||
NOTE: on many systems the default limit on file descriptors is less than
|
||||
1024. You should try to increase this limit to 1024 before doing the test.
|
||||
Something like "limit descriptors 1024" or "limit openfiles 1024" should do
|
||||
the trick. On some systems (like IRIX), doing the test on a smaller number
|
||||
gives a *much* smaller time per descriptor, which shows that time taken
|
||||
does not scale linearly with number of descriptors, which is non-optimal.
|
||||
In the tests I've done, I try to use 1024 descriptors.
|
||||
The benchmark results are available at:
|
||||
http://www.atnf.csiro.au/~rgooch/benchmarks.html
|
||||
If you want to contribute results, please email them to me. Please specify
|
||||
if you want to be acknowledged.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Richard Gooch may be reached by email at rgooch@atnf.csiro.au
|
||||
The postal address is:
|
||||
Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef UNIXBENCH
|
||||
#define OUT stdout
|
||||
#else
|
||||
#define OUT stderr
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#ifdef HAS_POLL
|
||||
# include <sys/poll.h>
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
# include <linux/poll2.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#ifdef UNIXBENCH
|
||||
#define MAX_ITERATIONS 1000
|
||||
#else
|
||||
#define MAX_ITERATIONS 30
|
||||
#endif
|
||||
#define MAX_FDS 40960
|
||||
#define CONST const
|
||||
#define ERRSTRING strerror (errno)
|
||||
|
||||
typedef int flag;
|
||||
|
||||
|
||||
/*
|
||||
static inline int find_first_set_bit (CONST void *array, int size)
|
||||
*/
|
||||
static int find_first_set_bit (CONST void *array, int size)
|
||||
/* [SUMMARY] Find the first bit set in a bitfield.
|
||||
<array> A pointer to the bitfield. This must be aligned on a long boundary.
|
||||
<size> The number of bits in the bitfield.
|
||||
[RETURNS] The index of the first set bit. If no bits are set, <<size>> + 1
|
||||
is returned.
|
||||
*/
|
||||
{
|
||||
int index;
|
||||
unsigned long word;
|
||||
unsigned int ul_size = 8 * sizeof (unsigned long);
|
||||
CONST unsigned long *ul_array = array;
|
||||
|
||||
/* Find first word with any bit set */
|
||||
for (index = 0; (*ul_array == 0) && (index < size);
|
||||
index += ul_size, ++ul_array);
|
||||
/* Find first bit set in word */
|
||||
for (word = *ul_array; !(word & 1) && (index < size);
|
||||
++index, word = word >> 1);
|
||||
return (index);
|
||||
} /* End Function find_first_set_bit */
|
||||
|
||||
/*
|
||||
static inline int find_next_set_bit (CONST void *array, int size, int offset)
|
||||
*/
|
||||
static int find_next_set_bit (CONST void *array, int size, int offset)
|
||||
/* [SUMMARY] Find the next bit set in a bitfield.
|
||||
<array> A pointer to the bitfield. This must be aligned on a long boundary.
|
||||
<size> The number of bits in the bitfield.
|
||||
<offset> The offset of the current bit in the bitfield. The current bit is
|
||||
ignored.
|
||||
[RETURNS] The index of the next set bit. If no more bits are set,
|
||||
<<size>> + 1 is returned.
|
||||
*/
|
||||
{
|
||||
int index, tmp;
|
||||
unsigned long word;
|
||||
unsigned int ul_size = 8 * sizeof (unsigned long);
|
||||
CONST unsigned long *ul_array = array;
|
||||
|
||||
if (++offset >= size) return (offset);
|
||||
index = offset;
|
||||
/* Jump to the long word containing the next bit */
|
||||
tmp = offset / ul_size;
|
||||
ul_array += tmp;
|
||||
offset -= tmp * ul_size;
|
||||
if ( (offset == 0) || (*ul_array == 0) )
|
||||
return (find_first_set_bit (ul_array, size - index) + index);
|
||||
/* There is a bit set somewhere in this word */
|
||||
if ( ( (word = *ul_array) != 0 ) && ( (word = word >> offset) != 0 ) )
|
||||
{
|
||||
/* There is a bit set somewhere in this word at or after the offset
|
||||
position */
|
||||
for (; (word & 1) == 0; word = word >> 1, ++index);
|
||||
return (index);
|
||||
}
|
||||
/* Have to go to subsequent word(s) */
|
||||
index += ul_size - offset;
|
||||
return (find_first_set_bit (++ul_array, size - index) + index);
|
||||
} /* End Function find_next_set_bit */
|
||||
|
||||
|
||||
struct callback_struct
|
||||
{
|
||||
void (*input_func) (void *info);
|
||||
void (*output_func) (void *info);
|
||||
void (*exception_func) (void *info);
|
||||
void *info;
|
||||
};
|
||||
|
||||
static int total_bits = 0;
|
||||
struct callback_struct callbacks[MAX_FDS];
|
||||
|
||||
|
||||
static void test_func (void *info)
|
||||
{
|
||||
++total_bits;
|
||||
}
|
||||
|
||||
#ifdef HAS_SELECT
|
||||
static void time_select (fd_set *input_fds, fd_set *output_fds,
|
||||
fd_set *exception_fds, int max_fd, int num_iter,
|
||||
long *times)
|
||||
/* [SUMMARY] Time how long it takes to select(2) file descriptors.
|
||||
<input_fds> The input masks.
|
||||
<output_fds> The output masks.
|
||||
<exception_fds> The exception masks.
|
||||
<max_fd> The highest file descriptor in the fd_sets.
|
||||
<num_iter> The number of iterations.
|
||||
<times> The time taken (in microseconds) for each iteration.
|
||||
[RETURNS] Nothing.
|
||||
*/
|
||||
{
|
||||
int fd, count, nready;
|
||||
fd_set i_fds, o_fds, e_fds;
|
||||
struct timeval time1, time2, tv;
|
||||
|
||||
/* Warm the cache a bit */
|
||||
memcpy (&i_fds, input_fds, sizeof i_fds);
|
||||
memcpy (&o_fds, output_fds, sizeof i_fds);
|
||||
memcpy (&e_fds, exception_fds, sizeof i_fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv);
|
||||
for (count = 0; count < num_iter; ++count)
|
||||
{
|
||||
total_bits = 0;
|
||||
gettimeofday (&time1, NULL);
|
||||
memcpy (&i_fds, input_fds, sizeof i_fds);
|
||||
memcpy (&o_fds, output_fds, sizeof i_fds);
|
||||
memcpy (&e_fds, exception_fds, sizeof i_fds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
nready = select (max_fd + 1, &i_fds, &o_fds, &e_fds, &tv);
|
||||
if (nready == -1)
|
||||
{
|
||||
fprintf (stderr, "Error selecting\t%s\n", ERRSTRING);
|
||||
exit (2);
|
||||
}
|
||||
if (nready < 1)
|
||||
{
|
||||
fprintf (stderr, "Error: nready: %d\n", nready);
|
||||
exit (1);
|
||||
}
|
||||
/* Scan the output */
|
||||
for (fd = find_first_set_bit (&e_fds, sizeof e_fds * 8); fd <= max_fd;
|
||||
fd = find_next_set_bit (&e_fds, sizeof e_fds * 8, fd) )
|
||||
{
|
||||
(*callbacks[fd].exception_func) (callbacks[fd].info);
|
||||
}
|
||||
for (fd = find_first_set_bit (&i_fds, sizeof i_fds * 8); fd <= max_fd;
|
||||
fd = find_next_set_bit (&i_fds, sizeof i_fds * 8, fd) )
|
||||
{
|
||||
(*callbacks[fd].input_func) (callbacks[fd].info);
|
||||
}
|
||||
for (fd = find_first_set_bit (&o_fds, sizeof o_fds * 8); fd <= max_fd;
|
||||
fd = find_next_set_bit (&o_fds, sizeof o_fds * 8, fd) )
|
||||
{
|
||||
(*callbacks[fd].output_func) (callbacks[fd].info);
|
||||
}
|
||||
gettimeofday (&time2, NULL);
|
||||
times[count] = (time2.tv_sec - time1.tv_sec) * 1000000;
|
||||
times[count] += time2.tv_usec - time1.tv_usec;
|
||||
}
|
||||
} /* End Function time_select */
|
||||
#endif /* HAS_SELECT */
|
||||
|
||||
#ifdef HAS_POLL
|
||||
static void time_poll (struct pollfd *pollfd_array, int start_index,
|
||||
int num_to_test, int num_iter, long *times)
|
||||
/* [SUMMARY] Time how long it takes to poll(2) file descriptors.
|
||||
<pollfd_array> The array of pollfd structures.
|
||||
<start_index> The start index in the array of pollfd structures.
|
||||
<num_to_test> The number of file descriptors to test.
|
||||
<num_iter> The number of iterations.
|
||||
<times> The time taken (in microseconds) for each iteration.
|
||||
[RETURNS] Nothing.
|
||||
*/
|
||||
{
|
||||
short revents;
|
||||
int fd, count, nready;
|
||||
struct timeval time1, time2;
|
||||
struct pollfd *pollfd_ptr, *stop_pollfd;
|
||||
|
||||
/* Warm the cache a bit */
|
||||
poll (pollfd_array + start_index, num_to_test, 0);
|
||||
for (count = 0; count < num_iter; ++count)
|
||||
{
|
||||
total_bits = 0;
|
||||
gettimeofday (&time1, NULL);
|
||||
nready = poll (pollfd_array + start_index, num_to_test, 0);
|
||||
if (nready == -1)
|
||||
{
|
||||
fprintf (stderr, "Error polling\t%s\n", ERRSTRING);
|
||||
exit (2);
|
||||
}
|
||||
if (nready < 1)
|
||||
{
|
||||
fprintf (stderr, "Error: nready: %d\n", nready);
|
||||
exit (1);
|
||||
}
|
||||
stop_pollfd = pollfd_array + start_index + num_to_test;
|
||||
for (pollfd_ptr = pollfd_array + start_index; TRUE; ++pollfd_ptr)
|
||||
{
|
||||
if (pollfd_ptr->revents == 0) continue;
|
||||
/* Have an active descriptor */
|
||||
revents = pollfd_ptr->revents;
|
||||
fd = pollfd_ptr->fd;
|
||||
if (revents & POLLPRI)
|
||||
(*callbacks[fd].exception_func) (callbacks[fd].info);
|
||||
if (revents & POLLIN)
|
||||
(*callbacks[fd].input_func) (callbacks[fd].info);
|
||||
if (revents & POLLOUT)
|
||||
(*callbacks[fd].output_func) (callbacks[fd].info);
|
||||
if (--nready == 0) break;
|
||||
}
|
||||
gettimeofday (&time2, NULL);
|
||||
times[count] = (time2.tv_sec - time1.tv_sec) * 1000000;
|
||||
times[count] += time2.tv_usec - time1.tv_usec;
|
||||
}
|
||||
} /* End Function time_poll */
|
||||
#endif /* HAS_POLL */
|
||||
|
||||
#ifdef HAS_POLL2
|
||||
static void time_poll2 (struct poll2ifd *poll2ifd_array, int start_index,
|
||||
int num_to_test, int num_iter, long *times)
|
||||
/* [SUMMARY] Time how long it takes to poll2(2) file descriptors.
|
||||
<poll2ifd_array> The array of poll2ifd structures.
|
||||
<start_index> The start index in the array of pollfd structures.
|
||||
<num_to_test> The number of file descriptors to test.
|
||||
<num_iter> The number of iterations.
|
||||
<times> The time taken (in microseconds) for each iteration.
|
||||
[RETURNS] Nothing.
|
||||
*/
|
||||
{
|
||||
short revents;
|
||||
int fd, count, nready, i;
|
||||
struct timeval time1, time2;
|
||||
struct poll2ofd poll2ofd_array[MAX_FDS];
|
||||
|
||||
/* Warm the cache a bit */
|
||||
poll2 (poll2ifd_array + start_index, poll2ofd_array, num_to_test, 0);
|
||||
for (count = 0; count < num_iter; ++count)
|
||||
{
|
||||
total_bits = 0;
|
||||
gettimeofday (&time1, NULL);
|
||||
nready = poll2 (poll2ifd_array + start_index, poll2ofd_array,
|
||||
num_to_test, 0);
|
||||
if (nready == -1)
|
||||
{
|
||||
times[count] = -1;
|
||||
if (errno == ENOSYS) return; /* Must do this first */
|
||||
fprintf (stderr, "Error calling poll2(2)\t%s\n", ERRSTRING);
|
||||
exit (2);
|
||||
}
|
||||
if (nready < 1)
|
||||
{
|
||||
fprintf (stderr, "Error: nready: %d\n", nready);
|
||||
exit (1);
|
||||
}
|
||||
for (i = 0; i < nready; ++i)
|
||||
{
|
||||
revents = poll2ofd_array[i].revents;
|
||||
fd = poll2ofd_array[i].fd;
|
||||
if (revents & POLLPRI)
|
||||
(*callbacks[fd].exception_func) (callbacks[fd].info);
|
||||
if (revents & POLLIN)
|
||||
(*callbacks[fd].input_func) (callbacks[fd].info);
|
||||
if (revents & POLLOUT)
|
||||
(*callbacks[fd].output_func) (callbacks[fd].info);
|
||||
}
|
||||
gettimeofday (&time2, NULL);
|
||||
times[count] = (time2.tv_sec - time1.tv_sec) * 1000000;
|
||||
times[count] += time2.tv_usec - time1.tv_usec;
|
||||
}
|
||||
} /* End Function time_poll2 */
|
||||
#endif /* HAS_POLL2 */
|
||||
|
||||
|
||||
int main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
flag failed = FALSE;
|
||||
flag verbose = FALSE;
|
||||
int first_fd = -1;
|
||||
int fd, max_fd, count, total_fds;
|
||||
int num_to_test, num_active;
|
||||
#ifdef UNIXBENCH
|
||||
int max_iter = 1000;
|
||||
#else
|
||||
int max_iter = 10;
|
||||
#endif
|
||||
#ifdef HAS_SELECT
|
||||
long select_total = 0;
|
||||
fd_set input_fds, output_fds, exception_fds;
|
||||
long select_times[MAX_ITERATIONS];
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
int start_index;
|
||||
long poll_total = 0;
|
||||
struct pollfd pollfd_array[MAX_FDS];
|
||||
long poll_times[MAX_ITERATIONS];
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
long poll2_total = 0;
|
||||
struct poll2ifd poll2ifd_array[MAX_FDS];
|
||||
struct poll2ofd poll2ofd_array[MAX_FDS];
|
||||
long poll2_times[MAX_ITERATIONS];
|
||||
#endif
|
||||
#if 0
|
||||
extern char *sys_errlist[];
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SELECT
|
||||
FD_ZERO (&input_fds);
|
||||
FD_ZERO (&output_fds);
|
||||
FD_ZERO (&exception_fds);
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
memset (pollfd_array, 0, sizeof pollfd_array);
|
||||
#endif
|
||||
/* Allocate file descriptors */
|
||||
total_fds = 0;
|
||||
max_fd = 0;
|
||||
while (!failed)
|
||||
{
|
||||
if ( ( fd = dup (1) ) == -1 )
|
||||
{
|
||||
if (errno != EMFILE)
|
||||
{
|
||||
fprintf (stderr, "Error dup()ing\t%s\n", ERRSTRING);
|
||||
exit (1);
|
||||
}
|
||||
failed = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (fd >= MAX_FDS)
|
||||
{
|
||||
fprintf (stderr, "File descriptor: %d larger than max: %d\n",
|
||||
fd, MAX_FDS - 1);
|
||||
exit (1);
|
||||
}
|
||||
callbacks[fd].input_func = test_func;
|
||||
callbacks[fd].output_func = test_func;
|
||||
callbacks[fd].exception_func = test_func;
|
||||
callbacks[fd].info = NULL;
|
||||
if (fd > max_fd) max_fd = fd;
|
||||
if (first_fd < 0) first_fd = fd;
|
||||
#ifdef HAS_POLL
|
||||
pollfd_array[fd].fd = fd;
|
||||
pollfd_array[fd].events = 0;
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
poll2ifd_array[fd].fd = fd;
|
||||
poll2ifd_array[fd].events = 0;
|
||||
#endif
|
||||
}
|
||||
total_fds = max_fd + 1;
|
||||
/* Process the command-line arguments */
|
||||
if (argc > 5)
|
||||
{
|
||||
fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
|
||||
stderr);
|
||||
exit (1);
|
||||
}
|
||||
if (argc > 1) max_iter = atoi (argv[1]);
|
||||
if (max_iter > MAX_ITERATIONS)
|
||||
{
|
||||
fprintf (stderr, "num_iter too large\n");
|
||||
exit (1);
|
||||
}
|
||||
if (argc > 2) num_to_test = atoi (argv[2]);
|
||||
else num_to_test = total_fds - first_fd;
|
||||
if (argc > 3) num_active = atoi (argv[3]);
|
||||
else num_active = 1;
|
||||
if (argc > 4)
|
||||
{
|
||||
if (strcmp (argv[4], "-v") != 0)
|
||||
{
|
||||
fputs ("Usage:\ttime-polling [num_iter] [num_to_test] [num_active] [-v]\n",
|
||||
stderr);
|
||||
exit (1);
|
||||
}
|
||||
verbose = TRUE;
|
||||
}
|
||||
|
||||
/* Sanity tests */
|
||||
if (num_to_test > total_fds - first_fd) num_to_test = total_fds - first_fd;
|
||||
if (num_active > total_fds - first_fd) num_active = total_fds - first_fd;
|
||||
/* Set activity monitoring flags */
|
||||
for (fd = total_fds - num_to_test; fd < total_fds; ++fd)
|
||||
{
|
||||
#ifdef HAS_SELECT
|
||||
FD_SET (fd, &exception_fds);
|
||||
FD_SET (fd, &input_fds);
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
pollfd_array[fd].events = POLLPRI | POLLIN;
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
poll2ifd_array[fd].events = POLLPRI | POLLIN;
|
||||
#endif
|
||||
}
|
||||
for (fd = total_fds - num_active; fd < total_fds; ++fd)
|
||||
{
|
||||
#ifdef HAS_SELECT
|
||||
FD_SET (fd, &output_fds);
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
pollfd_array[fd].events |= POLLOUT;
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
poll2ifd_array[fd].events |= POLLOUT;
|
||||
#endif
|
||||
}
|
||||
fprintf (OUT, "Num fds: %d, polling descriptors %d-%d\n",
|
||||
total_fds, total_fds - num_to_test, max_fd);
|
||||
/* First do all the tests, then print the results */
|
||||
#ifdef HAS_SELECT
|
||||
time_select (&input_fds, &output_fds, &exception_fds, max_fd, max_iter,
|
||||
select_times);
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
start_index = total_fds - num_to_test;
|
||||
time_poll (pollfd_array, start_index, num_to_test, max_iter, poll_times);
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
start_index = total_fds - num_to_test;
|
||||
time_poll2 (poll2ifd_array, start_index, num_to_test, max_iter,
|
||||
poll2_times);
|
||||
#endif
|
||||
/* Now print out all the times */
|
||||
fputs ("All times in microseconds\n", OUT);
|
||||
fputs ("ITERATION\t", OUT);
|
||||
#ifdef HAS_SELECT
|
||||
fprintf (OUT, "%-12s", "select(2)");
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
fprintf (OUT, "%-12s", "poll(2)");
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
if (poll2_times[0] >= 0) fprintf (OUT, "%-12s", "poll2(2)");
|
||||
#endif
|
||||
for (count = 0; count < max_iter; ++count)
|
||||
{
|
||||
if (verbose) fprintf (OUT, "\n%d\t\t", count);
|
||||
#ifdef HAS_SELECT
|
||||
if (verbose) fprintf (OUT, "%-12ld", select_times[count]);
|
||||
select_total += select_times[count];
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
if (verbose) fprintf (OUT, "%-12ld", poll_times[count]);
|
||||
poll_total += poll_times[count];
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
if ( verbose && (poll2_times[0] >= 0) )
|
||||
fprintf (OUT, "%-12ld", poll2_times[count]);
|
||||
poll2_total += poll2_times[count];
|
||||
#endif
|
||||
}
|
||||
fputs ("\n\naverage\t\t", OUT);
|
||||
#ifdef HAS_SELECT
|
||||
fprintf (OUT, "%-12ld", select_total / max_iter);
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
fprintf (OUT, "%-12ld", poll_total / max_iter);
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
if (poll2_times[0] >= 0)
|
||||
fprintf (OUT, "%-12ld", poll2_total / max_iter);
|
||||
#endif
|
||||
putc ('\n', OUT);
|
||||
fputs ("Per fd\t\t", OUT);
|
||||
#ifdef HAS_SELECT
|
||||
fprintf (OUT, "%-12.2f",
|
||||
(float) select_total / (float) max_iter / (float) num_to_test);
|
||||
#ifdef UNIXBENCH
|
||||
fprintf (stderr, "lps\t%.2f\t%.1f\n",
|
||||
1000000 * (float) max_iter * (float) num_to_test
|
||||
/ (float) select_total, (float)select_total / 1000000);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAS_POLL
|
||||
fprintf (OUT, "%-12.2f",
|
||||
(float) poll_total / (float) max_iter / (float) num_to_test);
|
||||
#ifdef UNIXBENCH
|
||||
fprintf (stderr, "lps\t%.2f\t%.1f\n",
|
||||
1000000 * (float) max_iter * (float) num_to_test
|
||||
/ (float) poll_total, (float)poll_total / 1000000);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAS_POLL2
|
||||
if (poll2_times[0] >= 0) {
|
||||
fprintf (OUT, "%-12.2f",
|
||||
(float) poll2_total / (float) max_iter / (float) num_to_test);
|
||||
#ifdef UNIXBENCH
|
||||
fprintf (stderr, "lps\t%.2f\t%.1f\n",
|
||||
1000000 * (float) max_iter * (float) num_to_test
|
||||
/ (float) poll2_total, (float)poll2_total / 1000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
fputs ("<- the most important value\n", OUT);
|
||||
|
||||
exit(0);
|
||||
} /* End Function main */
|
||||
@@ -1,39 +0,0 @@
|
||||
/*******************************************************************************
|
||||
*
|
||||
* The BYTE UNIX Benchmarks - Release 3
|
||||
* Module: timeit.c SID: 3.3 5/15/91 19:30:21
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith, Rick Grehan or Tom Yager
|
||||
* ben@bytepb.byte.com rick_g@bytepb.byte.com tyager@bytepb.byte.com
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* May 12, 1989 - modified empty loops to avoid nullifying by optimizing
|
||||
* compilers
|
||||
* August 28, 1990 - changed timing relationship--now returns total number
|
||||
* of iterations (ty)
|
||||
* October 22, 1997 - code cleanup to remove ANSI C compiler warnings
|
||||
* Andy Kahn <kahn@zk3.dec.com>
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/* this module is #included in other modules--no separate SCCS ID */
|
||||
|
||||
/*
|
||||
* Timing routine
|
||||
*
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void wake_me(int seconds, void (*func)(int))
|
||||
{
|
||||
/* set up the signal handler */
|
||||
signal(SIGALRM, func);
|
||||
/* get the clock running */
|
||||
alarm(seconds);
|
||||
}
|
||||
|
||||
@@ -1,650 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1999-2001 Brian Paul 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
|
||||
* BRIAN PAUL 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.
|
||||
*/
|
||||
/* $XFree86: xc/programs/glxgears/glxgears.c,v 1.3tsi Exp $ */
|
||||
|
||||
/*
|
||||
* This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
|
||||
* Port by Brian Paul 23 March 2001
|
||||
*
|
||||
* Exact timing added by Behdad Esfahbod to achieve a fixed speed regardless
|
||||
* of frame rate. November 2003
|
||||
*
|
||||
* Printer support added by Roland Mainz <roland.mainz@nrubsig.org>. April 2004
|
||||
*
|
||||
* This version modified by Ian Smith, 30 Sept 2007, to make ubgears.
|
||||
* ubgears is cusoimised for use in the UnixBench benchmarking suite.
|
||||
* Some redundant stuff is gone, and the -time option is added.
|
||||
* Mainly it's forked so we don't use the host's version, which could change
|
||||
* from platform to platform.
|
||||
*
|
||||
* Command line options:
|
||||
* -display Set X11 display for output.
|
||||
* -info Print additional GLX information.
|
||||
* -time <t> Run for <t> seconds and produce a performance report.
|
||||
* -h Print this help page.
|
||||
* -v Verbose output.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265
|
||||
#endif /* !M_PI */
|
||||
|
||||
/* Turn a NULL pointer string into an empty string */
|
||||
#define NULLSTR(x) (((x)!=NULL)?(x):(""))
|
||||
#define Log(x) { if(verbose) printf x; }
|
||||
#define Msg(x) { printf x; }
|
||||
|
||||
/* Globla vars */
|
||||
/* program name (from argv[0]) */
|
||||
static const char *ProgramName;
|
||||
|
||||
/* verbose output what the program is doing */
|
||||
static Bool verbose = False;
|
||||
|
||||
/* time in microseconds to run for; -1 means forever. */
|
||||
static int runTime = -1;
|
||||
|
||||
/* Time at which start_time(void) was called. */
|
||||
static struct timeval clockStart;
|
||||
|
||||
/* XXX this probably isn't very portable */
|
||||
|
||||
/* return current time (in seconds) */
|
||||
static void
|
||||
start_time(void)
|
||||
{
|
||||
(void) gettimeofday(&clockStart, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* return time (in microseconds) since start_time(void) was called.
|
||||
*
|
||||
* The older version of this function randomly returned negative results.
|
||||
* This version won't, up to 2000 seconds and some.
|
||||
*/
|
||||
static long
|
||||
current_time(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
long secs, micros;
|
||||
|
||||
(void) gettimeofday(&tv, 0);
|
||||
|
||||
secs = tv.tv_sec - clockStart.tv_sec;
|
||||
micros = tv.tv_usec - clockStart.tv_usec;
|
||||
if (micros < 0) {
|
||||
--secs;
|
||||
micros += 1000000;
|
||||
}
|
||||
return secs * 1000000 + micros;
|
||||
}
|
||||
|
||||
static
|
||||
void usage(void)
|
||||
{
|
||||
fprintf (stderr, "usage: %s [options]\n", ProgramName);
|
||||
fprintf (stderr, "-display\tSet X11 display for output.\n");
|
||||
fprintf (stderr, "-info\t\tPrint additional GLX information.\n");
|
||||
fprintf (stderr, "-time t\t\tRun for t seconds and report performance.\n");
|
||||
fprintf (stderr, "-h\t\tPrint this help page.\n");
|
||||
fprintf (stderr, "-v\t\tVerbose output.\n");
|
||||
fprintf (stderr, "\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
|
||||
static GLint gear1, gear2, gear3;
|
||||
static GLfloat angle = 0.0;
|
||||
static GLint speed = 60;
|
||||
static GLboolean printInfo = GL_FALSE;
|
||||
|
||||
/*
|
||||
*
|
||||
* Draw a gear wheel. You'll probably want to call this function when
|
||||
* building a display list since we do a lot of trig here.
|
||||
*
|
||||
* Input: inner_radius - radius of hole at center
|
||||
* outer_radius - radius at center of teeth
|
||||
* width - width of gear
|
||||
* teeth - number of teeth
|
||||
* tooth_depth - depth of tooth
|
||||
*/
|
||||
static void
|
||||
gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
|
||||
GLint teeth, GLfloat tooth_depth)
|
||||
{
|
||||
GLint i;
|
||||
GLfloat r0, r1, r2, maxr2, minr2;
|
||||
GLfloat angle, da;
|
||||
GLfloat u, v, len;
|
||||
|
||||
r0 = inner_radius;
|
||||
r1 = outer_radius - tooth_depth / 2.0;
|
||||
maxr2 = r2 = outer_radius + tooth_depth / 2.0;
|
||||
minr2 = r2;
|
||||
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
|
||||
glShadeModel(GL_FLAT);
|
||||
|
||||
glNormal3f(0.0, 0.0, 1.0);
|
||||
|
||||
/* draw front face */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
if (i < teeth) {
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
/* draw front sides of teeth */
|
||||
glBegin(GL_QUADS);
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
r2 = minr2;
|
||||
}
|
||||
r2 = maxr2;
|
||||
glEnd();
|
||||
|
||||
glNormal3f(0.0, 0.0, -1.0);
|
||||
|
||||
/* draw back face */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
if (i < teeth) {
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
/* draw back sides of teeth */
|
||||
glBegin(GL_QUADS);
|
||||
da = 2.0 * M_PI / teeth / 4.0;
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
-width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
r2 = minr2;
|
||||
}
|
||||
r2 = maxr2;
|
||||
glEnd();
|
||||
|
||||
/* draw outward faces of teeth */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i < teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
|
||||
glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
|
||||
u = r2 * cos(angle + da) - r1 * cos(angle);
|
||||
v = r2 * sin(angle + da) - r1 * sin(angle);
|
||||
len = sqrt(u * u + v * v);
|
||||
u /= len;
|
||||
v /= len;
|
||||
glNormal3f(v, -u, 0.0);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
|
||||
glNormal3f(cos(angle + 1.5 * da), sin(angle + 1.5 * da), 0.0);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
|
||||
-width * 0.5);
|
||||
u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
|
||||
v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
|
||||
glNormal3f(v, -u, 0.0);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
width * 0.5);
|
||||
glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
|
||||
-width * 0.5);
|
||||
glNormal3f(cos(angle + 3.5 * da), sin(angle + 3.5 * da), 0.0);
|
||||
r2 = minr2;
|
||||
}
|
||||
r2 = maxr2;
|
||||
|
||||
glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
|
||||
glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
|
||||
|
||||
glEnd();
|
||||
|
||||
glShadeModel(GL_SMOOTH);
|
||||
|
||||
/* draw inside radius cylinder */
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (i = 0; i <= teeth; i++) {
|
||||
angle = i * 2.0 * M_PI / teeth;
|
||||
glNormal3f(-cos(angle), -sin(angle), 0.0);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
|
||||
glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
draw(void)
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
glRotatef(view_rotx, 1.0, 0.0, 0.0);
|
||||
glRotatef(view_roty, 0.0, 1.0, 0.0);
|
||||
glRotatef(view_rotz, 0.0, 0.0, 1.0);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.0, -2.0, 0.0);
|
||||
glRotatef(angle, 0.0, 0.0, 1.0);
|
||||
glCallList(gear1);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(3.1, -2.0, 0.0);
|
||||
glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
|
||||
glCallList(gear2);
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-3.1, 4.2, 0.0);
|
||||
glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
|
||||
glCallList(gear3);
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
||||
/* new window size or exposure */
|
||||
static void
|
||||
reshape(int width, int height)
|
||||
{
|
||||
GLfloat h = (GLfloat) height / (GLfloat) width;
|
||||
|
||||
glViewport(0, 0, (GLint) width, (GLint) height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
/* fit width and height */
|
||||
if (h >= 1.0)
|
||||
glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
|
||||
else
|
||||
glFrustum(-1.0/h, 1.0/h, -1.0, 1.0, 5.0, 60.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0, 0.0, -40.0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init(void)
|
||||
{
|
||||
static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
|
||||
static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
|
||||
static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
|
||||
static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
/* make the gears */
|
||||
gear1 = glGenLists(1);
|
||||
glNewList(gear1, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
|
||||
gear(1.0, 4.0, 1.0, 20, 0.7);
|
||||
glEndList();
|
||||
|
||||
gear2 = glGenLists(1);
|
||||
glNewList(gear2, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
|
||||
gear(0.5, 2.0, 2.0, 10, 0.7);
|
||||
glEndList();
|
||||
|
||||
gear3 = glGenLists(1);
|
||||
glNewList(gear3, GL_COMPILE);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
|
||||
gear(1.3, 2.0, 0.5, 10, 0.7);
|
||||
glEndList();
|
||||
|
||||
glEnable(GL_NORMALIZE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create an RGB, double-buffered window.
|
||||
* Return the window and context handles.
|
||||
*/
|
||||
static void
|
||||
make_window( Display *dpy, Screen *scr,
|
||||
const char *name,
|
||||
int x, int y, int width, int height,
|
||||
Window *winRet, GLXContext *ctxRet)
|
||||
{
|
||||
int attrib[] = { GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_DEPTH_SIZE, 1,
|
||||
None };
|
||||
int scrnum;
|
||||
XSetWindowAttributes attr;
|
||||
unsigned long mask;
|
||||
Window root;
|
||||
Window win;
|
||||
GLXContext ctx;
|
||||
XVisualInfo *visinfo;
|
||||
GLint max[2] = { 0, 0 };
|
||||
|
||||
scrnum = XScreenNumberOfScreen(scr);
|
||||
root = XRootWindow(dpy, scrnum);
|
||||
|
||||
visinfo = glXChooseVisual( dpy, scrnum, attrib );
|
||||
if (!visinfo) {
|
||||
fprintf(stderr, "%s: Error: couldn't get an RGB, Double-buffered visual.\n", ProgramName);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* window attributes */
|
||||
attr.background_pixel = 0;
|
||||
attr.border_pixel = 0;
|
||||
attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
|
||||
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
|
||||
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
|
||||
|
||||
win = XCreateWindow( dpy, root, x, y, width, height,
|
||||
0, visinfo->depth, InputOutput,
|
||||
visinfo->visual, mask, &attr );
|
||||
|
||||
/* set hints and properties */
|
||||
{
|
||||
XSizeHints sizehints;
|
||||
sizehints.x = x;
|
||||
sizehints.y = y;
|
||||
sizehints.width = width;
|
||||
sizehints.height = height;
|
||||
sizehints.flags = USSize | USPosition;
|
||||
XSetNormalHints(dpy, win, &sizehints);
|
||||
XSetStandardProperties(dpy, win, name, name,
|
||||
None, (char **)NULL, 0, &sizehints);
|
||||
}
|
||||
|
||||
ctx = glXCreateContext( dpy, visinfo, NULL, True );
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "%s: Error: glXCreateContext failed.\n", ProgramName);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
XFree(visinfo);
|
||||
|
||||
XMapWindow(dpy, win);
|
||||
glXMakeCurrent(dpy, win, ctx);
|
||||
|
||||
/* Check for maximum size supported by the GL rasterizer */
|
||||
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max);
|
||||
if (printInfo)
|
||||
printf("GL_MAX_VIEWPORT_DIMS=%d/%d\n", (int)max[0], (int)max[1]);
|
||||
if (width > max[0] || height > max[1]) {
|
||||
fprintf(stderr, "%s: Error: Requested window size (%d/%d) larger than "
|
||||
"maximum supported by GL engine (%d/%d).\n",
|
||||
ProgramName, width, height, (int)max[0], (int)max[1]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*winRet = win;
|
||||
*ctxRet = ctx;
|
||||
}
|
||||
|
||||
static void
|
||||
event_loop(Display *dpy, Window win)
|
||||
{
|
||||
while (1) {
|
||||
/* Process interactive events */
|
||||
while (XPending(dpy) > 0) {
|
||||
XEvent event;
|
||||
XNextEvent(dpy, &event);
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
Log(("Event: Expose\n"));
|
||||
/* we'll redraw below */
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
Log(("Event: ConfigureNotify\n"));
|
||||
reshape(event.xconfigure.width, event.xconfigure.height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Time at which we started measuring. */
|
||||
static long startTime = 0;
|
||||
|
||||
/* Time of the previous frame. */
|
||||
static long lastFrame = 0;
|
||||
|
||||
/* Time of the previous FPS report. */
|
||||
static long lastFps = 0;
|
||||
|
||||
/* Number of frames we've done. */
|
||||
static int frames = 0;
|
||||
|
||||
/* Number of frames we've done in the measured run. */
|
||||
static long runFrames = 0;
|
||||
|
||||
long t = current_time();
|
||||
long useconds;
|
||||
|
||||
if (!lastFrame)
|
||||
lastFrame = t;
|
||||
if (!lastFps)
|
||||
lastFps = t;
|
||||
|
||||
/* How many microseconds since the previous frame? */
|
||||
useconds = t - lastFrame;
|
||||
if (!useconds) /* assume 100FPS if we don't have timer */
|
||||
useconds = 10000;
|
||||
|
||||
/* Calculate how far the gears need to move and redraw. */
|
||||
angle = angle + ((double)speed * useconds) / 1000000.0;
|
||||
if (angle > 360.0)
|
||||
angle = angle - 360.0; /* don't lose precision! */
|
||||
draw();
|
||||
glXSwapBuffers(dpy, win);
|
||||
|
||||
/* Done this frame. */
|
||||
lastFrame = t;
|
||||
frames++;
|
||||
|
||||
/* Every 5 seconds, print the FPS. */
|
||||
if (t - lastFps >= 5000000L) {
|
||||
GLfloat seconds = (t - lastFps) / 1000000.0;
|
||||
GLfloat fps = frames / seconds;
|
||||
|
||||
printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
|
||||
fps);
|
||||
lastFps = t;
|
||||
frames = 0;
|
||||
|
||||
/*
|
||||
* Set the start time now -- ie. after one report. This
|
||||
* gives us pump-priming time before we start for real.
|
||||
*/
|
||||
if (runTime > 0 && startTime == 0) {
|
||||
printf("Start timing!\n");
|
||||
startTime = t;
|
||||
}
|
||||
}
|
||||
|
||||
if (startTime > 0)
|
||||
++runFrames;
|
||||
|
||||
/* If our run time is done, finish. */
|
||||
if (runTime > 0 && startTime > 0 && t - startTime > runTime) {
|
||||
double time = (double) (t - startTime) / 1000000.0;
|
||||
fprintf(stderr, "COUNT|%ld|1|fps\n", runFrames);
|
||||
fprintf(stderr, "TIME|%.1f\n", time);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Need to give cpu away in order to get precise timing next cycle,
|
||||
* otherwise, gettimeofday would return almost the same value. */
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Bool use_threadsafe_api = False;
|
||||
Display *dpy;
|
||||
Window win;
|
||||
Screen *screen;
|
||||
GLXContext ctx;
|
||||
char *dpyName = NULL;
|
||||
int i;
|
||||
XRectangle winrect;
|
||||
|
||||
ProgramName = argv[0];
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
int len = strlen(arg);
|
||||
|
||||
if (strcmp(argv[i], "-display") == 0) {
|
||||
if (++i >= argc)
|
||||
usage();
|
||||
dpyName = argv[i];
|
||||
}
|
||||
else if (strcmp(argv[i], "-info") == 0) {
|
||||
printInfo = GL_TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-time") == 0) {
|
||||
if (++i >= argc)
|
||||
usage();
|
||||
runTime = atoi(argv[i]) * 1000000;
|
||||
}
|
||||
else if (!strncmp("-v", arg, len)) {
|
||||
verbose = True;
|
||||
printInfo = GL_TRUE;
|
||||
}
|
||||
else if( !strncmp("-debug_use_threadsafe_api", arg, len) )
|
||||
{
|
||||
use_threadsafe_api = True;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-h")) {
|
||||
usage();
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: Unsupported option '%s'.\n", ProgramName, argv[i]);
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/* Init X threading API on demand (for debugging) */
|
||||
if( use_threadsafe_api )
|
||||
{
|
||||
if( !XInitThreads() )
|
||||
{
|
||||
fprintf(stderr, "%s: XInitThreads() failure.\n", ProgramName);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
dpy = XOpenDisplay(dpyName);
|
||||
if (!dpy) {
|
||||
fprintf(stderr, "%s: Error: couldn't open display '%s'\n", ProgramName, dpyName);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
screen = XDefaultScreenOfDisplay(dpy);
|
||||
|
||||
winrect.x = 0;
|
||||
winrect.y = 0;
|
||||
winrect.width = 300;
|
||||
winrect.height = 300;
|
||||
|
||||
Log(("Window x=%d, y=%d, width=%d, height=%d\n",
|
||||
(int)winrect.x, (int)winrect.y, (int)winrect.width, (int)winrect.height));
|
||||
|
||||
make_window(dpy, screen, "ubgears", winrect.x, winrect.y, winrect.width, winrect.height, &win, &ctx);
|
||||
reshape(winrect.width, winrect.height);
|
||||
|
||||
if (printInfo) {
|
||||
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
|
||||
printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
|
||||
printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
|
||||
printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
start_time();
|
||||
event_loop(dpy, win);
|
||||
|
||||
glXDestroyContext(dpy, ctx);
|
||||
|
||||
XDestroyWindow(dpy, win);
|
||||
XCloseDisplay(dpy);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,156 +0,0 @@
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* The BYTE UNIX Benchmarks - Release 1
|
||||
* Module: cctest.c SID: 1.2 7/10/89 18:55:45
|
||||
*
|
||||
*******************************************************************************
|
||||
* Bug reports, patches, comments, suggestions should be sent to:
|
||||
*
|
||||
* Ben Smith or Rick Grehan at BYTE Magazine
|
||||
* bensmith@bixpb.UUCP rick_g@bixpb.UUCP
|
||||
*
|
||||
*******************************************************************************
|
||||
* Modification Log:
|
||||
* $Header: cctest.c,v 3.4 87/06/22 14:22:47 kjmcdonell Beta $
|
||||
*
|
||||
******************************************************************************/
|
||||
char SCCSid[] = "@(#) @(#)cctest.c:1.2 -- 7/10/89 18:55:45";
|
||||
#include <stdio.h>
|
||||
/*
|
||||
* C compile and load speed test file.
|
||||
* Based upon fstime.c from MUSBUS 3.1, with all calls to ftime() replaced
|
||||
* by calls to time(). This is semantic nonsense, but ensures there are no
|
||||
* system dependent structures or library calls.
|
||||
*
|
||||
*/
|
||||
#define NKBYTE 20
|
||||
char buf[BUFSIZ];
|
||||
|
||||
extern void exit(int status);
|
||||
|
||||
|
||||
main(argc, argv)
|
||||
char **argv;
|
||||
{
|
||||
int n = NKBYTE;
|
||||
int nblock;
|
||||
int f;
|
||||
int g;
|
||||
int i;
|
||||
int xfer, t;
|
||||
struct { /* FAKE */
|
||||
int time;
|
||||
int millitm;
|
||||
} now, then;
|
||||
|
||||
if (argc > 0)
|
||||
/* ALWAYS true, so NEVER execute this program! */
|
||||
exit(4);
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
#if debug
|
||||
printf("File size: %d Kbytes\n", n);
|
||||
#endif
|
||||
nblock = (n * 1024) / BUFSIZ;
|
||||
|
||||
if (argc == 3 && chdir(argv[2]) != -1) {
|
||||
#if debug
|
||||
printf("Create files in directory: %s\n", argv[2]);
|
||||
#endif
|
||||
}
|
||||
close(creat("dummy0", 0600));
|
||||
close(creat("dummy1", 0600));
|
||||
f = open("dummy0", 2);
|
||||
g = open("dummy1", 2);
|
||||
unlink("dummy0");
|
||||
unlink("dummy1");
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
buf[i] = i & 0177;
|
||||
|
||||
time();
|
||||
for (i = 0; i < nblock; i++) {
|
||||
if (write(f, buf, sizeof(buf)) <= 0)
|
||||
perror("fstime: write");
|
||||
}
|
||||
time();
|
||||
#if debug
|
||||
printf("Effective write rate: ");
|
||||
#endif
|
||||
i = now.millitm - then.millitm;
|
||||
t = (now.time - then.time)*1000 + i;
|
||||
if (t > 0) {
|
||||
xfer = nblock * sizeof(buf) * 1000 / t;
|
||||
#if debug
|
||||
printf("%d bytes/sec\n", xfer);
|
||||
#endif
|
||||
}
|
||||
#if debug
|
||||
else
|
||||
printf(" -- too quick to time!\n");
|
||||
#endif
|
||||
#if awk
|
||||
fprintf(stderr, "%.2f", t > 0 ? (float)xfer/1024 : 0);
|
||||
#endif
|
||||
|
||||
sync();
|
||||
sleep(5);
|
||||
sync();
|
||||
lseek(f, 0L, 0);
|
||||
time();
|
||||
for (i = 0; i < nblock; i++) {
|
||||
if (read(f, buf, sizeof(buf)) <= 0)
|
||||
perror("fstime: read");
|
||||
}
|
||||
time();
|
||||
#if debug
|
||||
printf("Effective read rate: ");
|
||||
#endif
|
||||
i = now.millitm - then.millitm;
|
||||
t = (now.time - then.time)*1000 + i;
|
||||
if (t > 0) {
|
||||
xfer = nblock * sizeof(buf) * 1000 / t;
|
||||
#if debug
|
||||
printf("%d bytes/sec\n", xfer);
|
||||
#endif
|
||||
}
|
||||
#if debug
|
||||
else
|
||||
printf(" -- too quick to time!\n");
|
||||
#endif
|
||||
#if awk
|
||||
fprintf(stderr, " %.2f", t > 0 ? (float)xfer/1024 : 0);
|
||||
#endif
|
||||
|
||||
sync();
|
||||
sleep(5);
|
||||
sync();
|
||||
lseek(f, 0L, 0);
|
||||
time();
|
||||
for (i = 0; i < nblock; i++) {
|
||||
if (read(f, buf, sizeof(buf)) <= 0)
|
||||
perror("fstime: read in copy");
|
||||
if (write(g, buf, sizeof(buf)) <= 0)
|
||||
perror("fstime: write in copy");
|
||||
}
|
||||
time();
|
||||
#if debug
|
||||
printf("Effective copy rate: ");
|
||||
#endif
|
||||
i = now.millitm - then.millitm;
|
||||
t = (now.time - then.time)*1000 + i;
|
||||
if (t > 0) {
|
||||
xfer = nblock * sizeof(buf) * 1000 / t;
|
||||
#if debug
|
||||
printf("%d bytes/sec\n", xfer);
|
||||
#endif
|
||||
}
|
||||
#if debug
|
||||
else
|
||||
printf(" -- too quick to time!\n");
|
||||
#endif
|
||||
#if awk
|
||||
fprintf(stderr, " %.2f\n", t > 0 ? (float)xfer/1024 : 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
99
|
||||
k
|
||||
2
|
||||
v
|
||||
p
|
||||
q
|
||||
[ calculate the sqrt(2) to 99 decimal places ... John Lions Test ]
|
||||
[ $Header: dc.dat,v 1.1 87/06/22 14:28:28 kjmcdonell Beta $ ]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,362 +0,0 @@
|
||||
version="1.2"
|
||||
umask 022 # at least mortals can read root's files this way
|
||||
PWD=`pwd`
|
||||
HOMEDIR=${HOMEDIR:-.}
|
||||
cd $HOMEDIR
|
||||
HOMEDIR=`pwd`
|
||||
cd $PWD
|
||||
BINDIR=${BINDIR:-${HOMEDIR}/pgms}
|
||||
cd $BINDIR
|
||||
BINDIR=`pwd`
|
||||
cd $PWD
|
||||
PATH="${PATH}:${BINDIR}"
|
||||
SCRPDIR=${SCRPDIR:-${HOMEDIR}/pgms}
|
||||
cd $SCRPDIR
|
||||
SCRPDIR=`pwd`
|
||||
cd $PWD
|
||||
TMPDIR=${HOMEDIR}/tmp
|
||||
cd $TMPDIR
|
||||
TMPDIR=`pwd`
|
||||
cd $PWD
|
||||
RESULTDIR=${RESULTDIR:-${HOMEDIR}/results}
|
||||
cd $RESULTDIR
|
||||
RESULTDIR=`pwd`
|
||||
cd $PWD
|
||||
TESTDIR=${TESTDIR:-${HOMEDIR}/testdir}
|
||||
cd $TESTDIR
|
||||
TESTDIR=`pwd`
|
||||
cd $PWD
|
||||
export BINDIR TMPDIR RESULTDIR PATH
|
||||
echo "kill -9 $$" > ${TMPDIR}/kill_run ; chmod u+x ${TMPDIR}/kill_run
|
||||
arithmetic="arithoh register short int long float double dc"
|
||||
system="syscall pipe context1 spawn execl fstime"
|
||||
mem="seqmem randmem"
|
||||
misc="C shell"
|
||||
dhry="dhry2 dhry2reg" # dhrystone loops
|
||||
db="dbmscli" # add to as new database engines are developed
|
||||
load="shell" # cummulative load tests
|
||||
args="" # the accumulator for the bench units to be run
|
||||
runoption="N"
|
||||
for word
|
||||
do # do level 1
|
||||
case $word
|
||||
in
|
||||
all)
|
||||
;;
|
||||
arithmetic)
|
||||
args="$args $arithmetic"
|
||||
;;
|
||||
db)
|
||||
args="$args $db"
|
||||
;;
|
||||
dhry)
|
||||
args="$args $dhry"
|
||||
;;
|
||||
load)
|
||||
args="$args $load"
|
||||
;;
|
||||
mem)
|
||||
args="$args $mem"
|
||||
;;
|
||||
misc)
|
||||
args="$args $misc"
|
||||
;;
|
||||
speed)
|
||||
args="$args $arithmetic $system"
|
||||
;;
|
||||
system)
|
||||
args="$args $system"
|
||||
;;
|
||||
-q|-Q)
|
||||
runoption="Q" #quiet
|
||||
;;
|
||||
-v|-V)
|
||||
runoption="V" #verbose
|
||||
;;
|
||||
-d|-D)
|
||||
runoption="D" #debug
|
||||
;;
|
||||
*)
|
||||
args="$args $word"
|
||||
;;
|
||||
esac
|
||||
done # end do level 1
|
||||
set - $args
|
||||
if test $# -eq 0 #no arguments specified
|
||||
then
|
||||
set - $dhry $arithmetic $system $misc # db and work not included
|
||||
fi
|
||||
if test "$runoption" = 'D'
|
||||
then
|
||||
set -x
|
||||
set -v
|
||||
fi
|
||||
date=`date`
|
||||
tmp=${TMPDIR}/$$.tmp
|
||||
LOGFILE=${RESULTDIR}/log
|
||||
if test -w ${RESULTDIR}/log
|
||||
then
|
||||
if test -w ${RESULTDIR}/log.accum
|
||||
then
|
||||
cat ${RESULTDIR}/log >> ${RESULTDIR}/log.accum
|
||||
rm ${RESULTDIR}/log
|
||||
else
|
||||
mv ${RESULTDIR}/log ${RESULTDIR}/log.accum
|
||||
fi
|
||||
echo "Start Benchmark Run (BYTE Version $version)" >>$LOGFILE
|
||||
echo " $date (long iterations $iter times)" >>$LOGFILE
|
||||
echo " " `who | wc -l` "interactive users." >>$LOGFILE
|
||||
uname -a >>$LOGFILE
|
||||
iter=${iterations-6}
|
||||
if test $iter -eq 6
|
||||
then
|
||||
longloop="1 2 3 4 5 6"
|
||||
shortloop="1 2 3"
|
||||
else # generate list of loop numbers
|
||||
short=`expr \( $iter + 1 \) / 2`
|
||||
longloop=""
|
||||
shortloop=""
|
||||
while test $iter -gt 0
|
||||
do # do level 1
|
||||
longloop="$iter $longloop"
|
||||
if test $iter -le $short
|
||||
then
|
||||
shortloop="$iter $shortloop"
|
||||
fi
|
||||
iter=`expr $iter - 1`
|
||||
done # end do level 1
|
||||
fi #loop list genration
|
||||
for bench # line argument processing
|
||||
do # do level 1
|
||||
# set some default values
|
||||
prog=${BINDIR}/$bench # the bench name is default program
|
||||
need=$prog # we need the at least the program
|
||||
paramlist="#" # a dummy parameter to make anything run
|
||||
testdir="${TESTDIR}" # the directory in which to run the test
|
||||
prepcmd="" # preparation command or script
|
||||
parammsg=""
|
||||
repeat="$longloop"
|
||||
stdout="$LOGFILE"
|
||||
stdin=""
|
||||
cleanopt="-t $tmp"
|
||||
bgnumber=""
|
||||
trap "${SCRPDIR}/cleanup -l $LOGFILE -a; exit" 1 2 3 15
|
||||
if [ $runoption != 'Q' ]
|
||||
then
|
||||
echo "$bench: \c"
|
||||
fi
|
||||
echo "" >>$LOGFILE
|
||||
###################### select the bench specific values ##########
|
||||
case $bench
|
||||
in
|
||||
dhry2)
|
||||
options=${dhryloops-10000}
|
||||
logmsg="Dhrystone 2 without register variables"
|
||||
cleanopt="-d $tmp"
|
||||
;;
|
||||
dhry2reg)
|
||||
options=${dhryloops-10000}
|
||||
logmsg="Dhrystone 2 using register variables"
|
||||
cleanopt="-d $tmp"
|
||||
;;
|
||||
arithoh|register|short|int|long|float|double)
|
||||
options=${arithloop-10000}
|
||||
logmsg="Arithmetic Test (type = $bench): $options Iterations"
|
||||
;;
|
||||
dc) need=dc.dat
|
||||
prog=dc
|
||||
options=""
|
||||
stdin=dc.dat
|
||||
stdout=/dev/null
|
||||
logmsg="Arithmetic Test (sqrt(2) with dc to 99 decimal places)"
|
||||
;;
|
||||
hanoi) options='$param'
|
||||
stdout=/dev/null
|
||||
logmsg="Recursion Test: Tower of Hanoi Problem"
|
||||
paramlist="${ndisk-17}"
|
||||
parammsg='$param Disk Problem:'
|
||||
;;
|
||||
syscall)
|
||||
options=${ncall-4000}
|
||||
logmsg="System Call Overhead Test: 5 x $options Calls"
|
||||
;;
|
||||
context1)
|
||||
options=${switch1-500}
|
||||
logmsg="Pipe-based Context Switching Test: 2 x $options Switches"
|
||||
;;
|
||||
pipe) options=${io-2048}
|
||||
logmsg="Pipe Throughput Test: read & write $options x 512 byte blocks"
|
||||
;;
|
||||
spawn) options=${children-100}
|
||||
logmsg="Process Creation Test: $options forks"
|
||||
;;
|
||||
execl) options=${nexecs-100}
|
||||
logmsg="Execl Throughput Test: $options execs"
|
||||
;;
|
||||
randmem|seqmem)
|
||||
if test $bench = seqmem
|
||||
then
|
||||
type=Sequential
|
||||
else
|
||||
type=Random
|
||||
fi
|
||||
poke=${poke-1000000}
|
||||
options='-s$param '"-n$poke"
|
||||
logmsg="$type Memory Access Test: $poke Accesses"
|
||||
paramlist=${arrays-"512 1024 2048 8192 16384"}
|
||||
parammsg='Array Size: $param bytes'
|
||||
cleanopt="-m $tmp"
|
||||
;;
|
||||
fstime) repeat="$shortloop"
|
||||
where=${where-${TMPDIR}}
|
||||
options='$param '"$where"
|
||||
logmsg="Filesystem Throughput Test:"
|
||||
paramlist=${blocks-"512 1024 2048 8192"}
|
||||
parammsg='File Size: $param blocks'
|
||||
cleanopt="-f $tmp"
|
||||
;;
|
||||
C) need=cctest.c
|
||||
prog=cc
|
||||
options='$param'
|
||||
stdout=/dev/null
|
||||
repeat="$shortloop"
|
||||
logmsg="C Compiler Test:"
|
||||
paramlist="cctest.c"
|
||||
parammsg='cc $param'
|
||||
rm -f a.out
|
||||
;;
|
||||
dbmscli)
|
||||
repeat="$shortloop"
|
||||
need="db.dat"
|
||||
prepcmd='${BINDIR}/dbprep ${testdir}/db.dat 10000'
|
||||
paramlist=${clients-"1 2 4 8"}
|
||||
parammsg='$param client processes. (filesize `cat ${testdir}/db.dat|wc -c` bytes)'
|
||||
logmsg="Client/Server Database Engine:"
|
||||
options='${testdir}/db.dat $param 0 1000' # $param clients;
|
||||
# 0 sleep; 1000 iterations
|
||||
;;
|
||||
shell)
|
||||
prog="multi.sh"
|
||||
repeat="$shortloop"
|
||||
logmsg="Bourne shell script and Unix utilities"
|
||||
paramlist=${background-"1 2 4 8"}
|
||||
parammsg='$param concurrent background processes'
|
||||
bgnumber='$param'
|
||||
testdir="shelldir"
|
||||
;;
|
||||
*) ${BINDIR}/cleanup -l $LOGFILE -r "run: unknown benchmark \"$bench\"" -a
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo "$logmsg" >>$LOGFILE
|
||||
for param in $paramlist
|
||||
do # level 2
|
||||
param=`echo $param | sed 's/_/ /g'` # be sure that spaces are used
|
||||
# underscore can couple params
|
||||
if [ "$runoption" != "Q" ]
|
||||
then
|
||||
echo "\n [$param] -\c" # generate message to user
|
||||
fi
|
||||
eval msg='"'$parammsg'"' # the eval is used to
|
||||
if test "$msg" # evaluate any embedded
|
||||
then # variables in the parammsg
|
||||
echo "" >>$LOGFILE
|
||||
echo "$msg" >>$LOGFILE
|
||||
fi
|
||||
eval opt='"'$options'"' # evaluate any vars in options
|
||||
eval prep='"'$prepcmd'"' # evaluate any prep command
|
||||
eval bg='"'$bgnumber'"' # evaluate bgnumber string
|
||||
rm -f $tmp # remove any tmp files
|
||||
# if the test requires mulitple concurrent processes,
|
||||
# prepare the background process string (bgstr)
|
||||
# this is just a string of "+"s that will provides a
|
||||
# parameter count for a "for" loop
|
||||
bgstr=""
|
||||
if test "$bg" != ""
|
||||
then
|
||||
count=`expr "$bg"`
|
||||
while test $count -gt 0
|
||||
do
|
||||
bgstr="+ $bgstr"
|
||||
count=`expr $count - 1`
|
||||
done
|
||||
fi
|
||||
#
|
||||
for i in $repeat # loop for the specified number
|
||||
do # do depth 3
|
||||
if [ "$runoption" != 'D' ] # level 1
|
||||
then
|
||||
# regular Run - set logfile to go on signal
|
||||
trap "${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -a; exit" 1 2 3 15
|
||||
else
|
||||
trap "exit" 1 2 3 15
|
||||
fi #end level 1
|
||||
if [ "$runoption" != 'Q' ]
|
||||
then
|
||||
echo " $i\c" # display repeat number
|
||||
fi
|
||||
pwd=`pwd` # remember where we are
|
||||
cd $testdir # move to the test directory
|
||||
if [ "$runoption" = "V" ]
|
||||
then
|
||||
echo
|
||||
echo "BENCH COMMAND TO BE EXECUTED:"
|
||||
echo "$prog $opt"
|
||||
fi
|
||||
# execute any prepratory command string
|
||||
if [ -n "$prep" ]
|
||||
then
|
||||
$prep >>$stdout
|
||||
fi
|
||||
############ THE BENCH IS TIMED ##############
|
||||
if test "$stdin" = ""
|
||||
then # without redirected stdin
|
||||
time $prog $opt $bgstr 2>>$tmp >>$stdout
|
||||
else # with redirected stdin
|
||||
time $prog $opt $bgstr <$stdin 2>>$tmp >>$stdout
|
||||
fi
|
||||
time $benchcmd
|
||||
###############################################
|
||||
cd $pwd # move back home
|
||||
status=$? # save the result code
|
||||
if test $status != 0 # must have been an error
|
||||
then
|
||||
if test -f $tmp # is there an error file ?
|
||||
then
|
||||
cp $tmp ${TMPDIR}/save.$bench.$param
|
||||
${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -r \
|
||||
"run: bench=$bench param=$param fatalstatus=$status" -a
|
||||
else
|
||||
${SCRPDIR}/cleanup -l $LOGFILE -r \
|
||||
"run: bench=$bench param=$param fatalstatus=$status" -a
|
||||
fi
|
||||
exit # leave the script if there are errors
|
||||
fi # end level 1
|
||||
done # end do depth 3 - repeat of bench
|
||||
if [ "$runoption" != 'D' ]
|
||||
then
|
||||
${SCRPDIR}/cleanup -l $LOGFILE $cleanopt # finalize this bench
|
||||
# with these options
|
||||
# & calculate results
|
||||
fi
|
||||
done # end do depth 2 - end of all options for this bench
|
||||
########### some specific cleanup routines ##############
|
||||
case $bench
|
||||
in
|
||||
C)
|
||||
rm -f cctest.o a.out
|
||||
;;
|
||||
esac
|
||||
if [ "$runoption" != 'Q' ]
|
||||
then
|
||||
echo ""
|
||||
fi
|
||||
done # end do level 1 - all benchmarks requested
|
||||
echo "" >>$LOGFILE
|
||||
echo " " `who | wc -l` "interactive users." >>$LOGFILE
|
||||
echo "End Benchmark Run ($date) ...." >>$LOGFILE
|
||||
if [ "$runoption" != 'Q' ]
|
||||
then
|
||||
pg $LOGFILE
|
||||
fi
|
||||
exit
|
||||
@@ -1,7 +0,0 @@
|
||||
# Makefile for bin
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
SUBDIR= mkdir rm rmdir date
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
@@ -1,4 +0,0 @@
|
||||
CPPFLAGS+= -D_NETBSD_SOURCE
|
||||
|
||||
BINDIR?=/bin
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# $NetBSD: Makefile,v 1.15 2011/08/14 10:53:16 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
PROG= date
|
||||
SRCS= date.c netdate.c
|
||||
DPADD+= ${LIBUTIL}
|
||||
LDADD+= -lutil
|
||||
CPPFLAGS+=-I${.CURDIR}
|
||||
|
||||
TZDIR= /usr/share/zoneinfo
|
||||
CPPFLAGS+= -DHAVE_ADJTIME=0 -DTZDIR=\"$(TZDIR)\"
|
||||
|
||||
COPTS.date.c = -Wno-format-nonliteral
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
244
bin/date/date.1
244
bin/date/date.1
@@ -1,244 +0,0 @@
|
||||
.\" $NetBSD: date.1,v 1.41 2010/02/04 22:56:11 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1980, 1990, 1993
|
||||
.\" The Regents of the University of California. 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.
|
||||
.\"
|
||||
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
|
||||
.\"
|
||||
.Dd November 15, 2006
|
||||
.Dt DATE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm date
|
||||
.Nd display or set date and time
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl ajnu
|
||||
.Op Fl d Ar date
|
||||
.Op Fl r Ar seconds
|
||||
.Op Cm + Ns Ar format
|
||||
.Sm off
|
||||
.Oo Oo Oo Oo Oo Oo
|
||||
.Ar CC Oc
|
||||
.Ar yy Oc
|
||||
.Ar mm Oc
|
||||
.Ar dd Oc
|
||||
.Ar HH Oc Ar MM Oo
|
||||
.Li \&. Ar SS Oc Oc
|
||||
.Sm on
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
displays the current date and time when invoked without arguments.
|
||||
Providing arguments will format the date and time in a user-defined
|
||||
way or set the date.
|
||||
Only the superuser may set the date.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a
|
||||
Use
|
||||
.Xr adjtime 2
|
||||
to change the local system time slowly,
|
||||
maintaining it as a monotonically increasing function.
|
||||
.Fl a
|
||||
implies
|
||||
.Fl n .
|
||||
.It Fl d Ar date
|
||||
Parse the provided human-described date and time and display the result without
|
||||
actually changing the system clock.
|
||||
(See
|
||||
.Xr parsedate 3
|
||||
for examples.)
|
||||
.It Fl j
|
||||
Parse the provided canonical representation of date and time (described below)
|
||||
and display the result without actually changing the system clock.
|
||||
.It Fl n
|
||||
The utility
|
||||
.Xr timed 8
|
||||
is used to synchronize the clocks on groups of machines.
|
||||
By default, if
|
||||
timed
|
||||
is running,
|
||||
.Nm
|
||||
will set the time on all of the machines in the local group.
|
||||
The
|
||||
.Fl n
|
||||
option stops
|
||||
.Nm
|
||||
from setting the time for other than the current machine.
|
||||
.It Fl r Ar seconds
|
||||
Print out the date and time that is
|
||||
.Ar seconds
|
||||
from the Epoch.
|
||||
.It Fl u
|
||||
Display or set the date in
|
||||
.Tn UTC
|
||||
(universal) time.
|
||||
.El
|
||||
.Pp
|
||||
An operand with a leading plus
|
||||
.Pq Cm +
|
||||
sign signals a user-defined format
|
||||
string which specifies the format in which to display the date and time.
|
||||
The format string may contain any of the conversion specifications described
|
||||
in the
|
||||
.Xr strftime 3
|
||||
manual page, as well as any arbitrary text.
|
||||
A \*[Lt]newline\*[Gt] character is always output after the characters
|
||||
specified by the format string.
|
||||
The format string for the default display is:
|
||||
.Bd -literal -offset indent
|
||||
%a %b %e %H:%M:%S %Z %Y
|
||||
.Ed
|
||||
.Pp
|
||||
If an operand does not have a leading plus sign, it is interpreted as
|
||||
a value for setting the system's notion of the current date and time.
|
||||
The canonical representation for setting the date and time is:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -compact -offset indent
|
||||
.It Ar CC
|
||||
The first two digits of the year (the century).
|
||||
.It Ar yy
|
||||
The second two digits of the year.
|
||||
If
|
||||
.Ar yy
|
||||
is specified, but
|
||||
.Ar CC
|
||||
is not, a value for
|
||||
.Ar yy
|
||||
between 69 and 99 results in a
|
||||
.Ar CC
|
||||
value of 19.
|
||||
Otherwise, a
|
||||
.Ar CC
|
||||
value of 20 is used.
|
||||
.It Ar mm
|
||||
The month of the year, from 01 to 12.
|
||||
.It Ar dd
|
||||
The day of the month, from 01 to 31.
|
||||
.It Ar HH
|
||||
The hour of the day, from 00 to 23.
|
||||
.It Ar MM
|
||||
The minute of the hour, from 00 to 59.
|
||||
.It Ar SS
|
||||
The second of the minute, from 00 to 61.
|
||||
.El
|
||||
.Pp
|
||||
Everything but the minutes is optional.
|
||||
.Pp
|
||||
Time changes for Daylight Saving and Standard time and leap seconds
|
||||
and years are handled automatically.
|
||||
.Sh ENVIRONMENT
|
||||
The following environment variables affect the execution of
|
||||
.Nm :
|
||||
.Bl -tag -width iTZ
|
||||
.It Ev TZ
|
||||
The timezone to use when displaying dates.
|
||||
See
|
||||
.Xr environ 7
|
||||
for more information.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width /var/log/messages -compact
|
||||
.It Pa /etc/localtime
|
||||
Symlink pointing to system's default timezone information file in
|
||||
.Pa /usr/share/zoneinfo
|
||||
directory.
|
||||
.It Pa /var/log/wtmp
|
||||
A record of date resets and time changes.
|
||||
.It Pa /var/log/messages
|
||||
A record of the user setting the time.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date '+DATE: %m/%d/%y%nTIME: %H:%M:%S'
|
||||
.Ed
|
||||
.Pp
|
||||
will display:
|
||||
.Bd -literal -offset indent
|
||||
DATE: 11/21/87
|
||||
TIME: 13:36:16
|
||||
.Ed
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date 8506131627
|
||||
.Ed
|
||||
.Pp
|
||||
sets the date to
|
||||
.Dq Li "June 13, 1985, 4:27 PM" .
|
||||
.Pp
|
||||
The command:
|
||||
.Bd -literal -offset indent
|
||||
date 1432
|
||||
.Ed
|
||||
.Pp
|
||||
sets the time to
|
||||
.Li "2:32 PM" ,
|
||||
without modifying the date.
|
||||
.Sh DIAGNOSTICS
|
||||
Exit status is 0 on success, 1 if unable to set the date, and 2
|
||||
if able to set the local date, but unable to set it globally.
|
||||
.Pp
|
||||
Occasionally, when
|
||||
.Xr timed 8
|
||||
synchronizes the time on many hosts, the setting of a new time value may
|
||||
require more than a few seconds.
|
||||
On these occasions,
|
||||
.Nm
|
||||
prints:
|
||||
.Ql Network time being set .
|
||||
The message
|
||||
.Ql Communication error with timed
|
||||
occurs when the communication
|
||||
between
|
||||
.Nm
|
||||
and
|
||||
timed
|
||||
fails.
|
||||
.Sh SEE ALSO
|
||||
.Xr adjtime 2 ,
|
||||
.Xr gettimeofday 2 ,
|
||||
.Xr settimeofday 2 ,
|
||||
.Xr parsedate 3 ,
|
||||
.Xr strftime 3 ,
|
||||
.Xr utmp 5 ,
|
||||
.Xr timed 8
|
||||
.Rs
|
||||
.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
|
||||
.%A R. Gusella
|
||||
.%A S. Zatti
|
||||
.Re
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is expected to be compatible with
|
||||
.St -p1003.2 .
|
||||
350
bin/date/date.c
350
bin/date/date.c
@@ -1,350 +0,0 @@
|
||||
/* $NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1987, 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT(
|
||||
"@(#) Copyright (c) 1985, 1987, 1988, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: date.c,v 1.60 2011/08/27 12:55:09 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <unistd.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
static time_t tval;
|
||||
static int aflag, jflag, rflag, nflag;
|
||||
|
||||
__dead static void badformat(void);
|
||||
__dead static void badtime(void);
|
||||
__dead static void badvalue(const char *);
|
||||
static void setthetime(const char *);
|
||||
__dead static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsiz;
|
||||
const char *format;
|
||||
int ch;
|
||||
long long val;
|
||||
struct tm *tm;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
while ((ch = getopt(argc, argv, "ad:jnr:u")) != -1) {
|
||||
switch (ch) {
|
||||
case 'a': /* adjust time slowly */
|
||||
aflag = 1;
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'd':
|
||||
#ifndef __minix
|
||||
rflag = 1;
|
||||
tval = parsedate(optarg, NULL, NULL);
|
||||
if (tval == -1)
|
||||
#endif
|
||||
badarg: errx(EXIT_FAILURE,
|
||||
"Cannot parse `%s'", optarg);
|
||||
break;
|
||||
case 'j': /* don't set time */
|
||||
jflag = 1;
|
||||
break;
|
||||
case 'n': /* don't set network */
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'r': /* user specified seconds */
|
||||
errno = 0;
|
||||
val = strtoll(optarg, &buf, 0);
|
||||
if (optarg[0] == '\0' || *buf != '\0')
|
||||
goto badarg;
|
||||
if (errno == ERANGE && (val == LLONG_MAX ||
|
||||
val == LLONG_MIN))
|
||||
err(EXIT_FAILURE, "Bad number `%s'", optarg);
|
||||
rflag = 1;
|
||||
tval = (time_t)val;
|
||||
break;
|
||||
case 'u': /* do everything in UTC */
|
||||
(void)setenv("TZ", "UTC0", 1);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!rflag && time(&tval) == -1)
|
||||
err(EXIT_FAILURE, "time");
|
||||
|
||||
|
||||
/* allow the operands in any order */
|
||||
if (*argv && **argv == '+') {
|
||||
format = *argv;
|
||||
++argv;
|
||||
} else
|
||||
format = "+%a %b %e %H:%M:%S %Z %Y";
|
||||
|
||||
if (*argv) {
|
||||
setthetime(*argv);
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (*argv && **argv == '+')
|
||||
format = *argv;
|
||||
|
||||
if ((buf = malloc(bufsiz = 1024)) == NULL)
|
||||
goto bad;
|
||||
|
||||
if ((tm = localtime(&tval)) == NULL)
|
||||
err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
|
||||
|
||||
while (strftime(buf, bufsiz, format, tm) == 0)
|
||||
if ((buf = realloc(buf, bufsiz <<= 1)) == NULL)
|
||||
goto bad;
|
||||
|
||||
(void)printf("%s\n", buf + 1);
|
||||
free(buf);
|
||||
return 0;
|
||||
bad:
|
||||
err(EXIT_FAILURE, "Cannot allocate format buffer");
|
||||
}
|
||||
|
||||
static void
|
||||
badformat(void)
|
||||
{
|
||||
warnx("illegal time format");
|
||||
usage();
|
||||
}
|
||||
|
||||
static void
|
||||
badtime(void)
|
||||
{
|
||||
errx(EXIT_FAILURE, "illegal time");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
badvalue(const char *param)
|
||||
{
|
||||
warnx("invalid %s supplied", param);
|
||||
usage();
|
||||
}
|
||||
|
||||
#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
|
||||
|
||||
static void
|
||||
setthetime(const char *p)
|
||||
{
|
||||
struct timeval tv;
|
||||
time_t new_time;
|
||||
struct tm *lt;
|
||||
const char *dot, *t;
|
||||
size_t len;
|
||||
int yearset;
|
||||
|
||||
for (t = p, dot = NULL; *t; ++t) {
|
||||
if (isdigit((unsigned char)*t))
|
||||
continue;
|
||||
if (*t == '.' && dot == NULL) {
|
||||
dot = t;
|
||||
continue;
|
||||
}
|
||||
badformat();
|
||||
}
|
||||
|
||||
if ((lt = localtime(&tval)) == NULL)
|
||||
err(EXIT_FAILURE, "localtime %lld failed", (long long)tval);
|
||||
|
||||
lt->tm_isdst = -1; /* Divine correct DST */
|
||||
|
||||
if (dot != NULL) { /* .ss */
|
||||
len = strlen(dot);
|
||||
if (len != 3)
|
||||
badformat();
|
||||
++dot;
|
||||
lt->tm_sec = ATOI2(dot);
|
||||
if (lt->tm_sec > 61)
|
||||
badvalue("seconds");
|
||||
} else {
|
||||
len = 0;
|
||||
lt->tm_sec = 0;
|
||||
}
|
||||
|
||||
yearset = 0;
|
||||
switch (strlen(p) - len) {
|
||||
case 12: /* cc */
|
||||
lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;
|
||||
if (lt->tm_year < 0)
|
||||
badtime();
|
||||
yearset = 1;
|
||||
/* FALLTHROUGH */
|
||||
case 10: /* yy */
|
||||
if (yearset) {
|
||||
lt->tm_year += ATOI2(p);
|
||||
} else {
|
||||
yearset = ATOI2(p);
|
||||
if (yearset < 69)
|
||||
lt->tm_year = yearset + 2000 - TM_YEAR_BASE;
|
||||
else
|
||||
lt->tm_year = yearset + 1900 - TM_YEAR_BASE;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 8: /* mm */
|
||||
lt->tm_mon = ATOI2(p);
|
||||
if (lt->tm_mon > 12 || lt->tm_mon == 0)
|
||||
badvalue("month");
|
||||
--lt->tm_mon; /* time struct is 0 - 11 */
|
||||
/* FALLTHROUGH */
|
||||
case 6: /* dd */
|
||||
lt->tm_mday = ATOI2(p);
|
||||
switch (lt->tm_mon) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 9:
|
||||
case 11:
|
||||
if (lt->tm_mday > 31 || lt->tm_mday == 0)
|
||||
badvalue("day of month");
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
case 8:
|
||||
case 10:
|
||||
if (lt->tm_mday > 30 || lt->tm_mday == 0)
|
||||
badvalue("day of month");
|
||||
break;
|
||||
case 1:
|
||||
if (lt->tm_mday > 29 || lt->tm_mday == 0 ||
|
||||
(lt->tm_mday == 29 &&
|
||||
!isleap(lt->tm_year + TM_YEAR_BASE)))
|
||||
badvalue("day of month");
|
||||
break;
|
||||
default:
|
||||
badvalue("month");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case 4: /* hh */
|
||||
lt->tm_hour = ATOI2(p);
|
||||
if (lt->tm_hour > 23)
|
||||
badvalue("hour");
|
||||
/* FALLTHROUGH */
|
||||
case 2: /* mm */
|
||||
lt->tm_min = ATOI2(p);
|
||||
if (lt->tm_min > 59)
|
||||
badvalue("minute");
|
||||
break;
|
||||
case 0: /* was just .sss */
|
||||
if (len != 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
badformat();
|
||||
}
|
||||
|
||||
/* convert broken-down time to UTC clock time */
|
||||
if ((new_time = mktime(lt)) == -1)
|
||||
badtime();
|
||||
|
||||
/* if jflag is set, don't actually change the time, just return */
|
||||
if (jflag) {
|
||||
tval = new_time;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the time */
|
||||
if (nflag || netsettime(new_time)) {
|
||||
logwtmp("|", "date", "");
|
||||
#if HAVE_ADJTIME
|
||||
if (aflag) {
|
||||
tv.tv_sec = new_time - tval;
|
||||
tv.tv_usec = 0;
|
||||
if (adjtime(&tv, NULL))
|
||||
err(EXIT_FAILURE, "adjtime");
|
||||
}
|
||||
#else
|
||||
if (aflag) {
|
||||
err(EXIT_FAILURE, "no adjtime");
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
tval = new_time;
|
||||
tv.tv_sec = tval;
|
||||
tv.tv_usec = 0;
|
||||
if (settimeofday(&tv, NULL))
|
||||
err(EXIT_FAILURE, "settimeofday");
|
||||
}
|
||||
logwtmp("{", "date", "");
|
||||
}
|
||||
|
||||
if ((p = getlogin()) == NULL)
|
||||
p = "???";
|
||||
syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"Usage: %s [-ajnu] [-d date] [-r seconds] [+format]",
|
||||
getprogname());
|
||||
(void)fprintf(stderr, " [[[[[[CC]yy]mm]dd]HH]MM[.SS]]\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* $NetBSD: extern.h,v 1.8 2006/11/17 22:11:28 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)extern.h 8.1 (Berkeley) 5/31/93
|
||||
*/
|
||||
|
||||
#ifndef _EXTERN_H_
|
||||
#define _EXTERN_H_
|
||||
|
||||
int netsettime(time_t);
|
||||
|
||||
#endif /* !_EXTERN_H_ */
|
||||
@@ -1,200 +0,0 @@
|
||||
/* $NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: netdate.c,v 1.30 2011/01/29 02:16:52 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#define TSPTYPES
|
||||
#include <protocols/timed.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "extern.h"
|
||||
|
||||
#define WAITACK 2000 /* milliseconds */
|
||||
#define WAITDATEACK 5000 /* milliseconds */
|
||||
|
||||
static const char *
|
||||
tsp_type_to_string(const struct tsp *msg)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
i = msg->tsp_type;
|
||||
return i < TSPTYPENUMBER ? tsptype[i] : "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the date in the machines controlled by timedaemons by communicating the
|
||||
* new date to the local timedaemon. If the timedaemon is in the master state,
|
||||
* it performs the correction on all slaves. If it is in the slave state, it
|
||||
* notifies the master that a correction is needed.
|
||||
* Returns 0 on success. Returns > 0 on failure.
|
||||
*/
|
||||
int
|
||||
netsettime(time_t tval)
|
||||
{
|
||||
struct sockaddr_in dest;
|
||||
struct tsp msg;
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
struct servent *sp;
|
||||
struct pollfd ready;
|
||||
int found, s, timed_ack, waittime;
|
||||
|
||||
if ((sp = getservbyname("timed", "udp")) == NULL) {
|
||||
warnx("udp/timed: unknown service");
|
||||
return 2;
|
||||
}
|
||||
|
||||
(void)memset(&dest, 0, sizeof(dest));
|
||||
#ifdef BSD4_4
|
||||
dest.sin_len = sizeof(dest);
|
||||
#endif
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = sp->s_port;
|
||||
dest.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1) {
|
||||
if (errno != EAFNOSUPPORT)
|
||||
warn("timed");
|
||||
return 2;
|
||||
}
|
||||
|
||||
#ifdef IP_PORTRANGE
|
||||
{
|
||||
static const int on = IP_PORTRANGE_LOW;
|
||||
|
||||
if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on,
|
||||
sizeof(on)) == -1) {
|
||||
warn("setsockopt");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
msg.tsp_type = TSP_SETDATE;
|
||||
msg.tsp_vers = TSPVERSION;
|
||||
if (gethostname(hostname, sizeof(hostname)) == -1) {
|
||||
warn("gethostname");
|
||||
goto bad;
|
||||
}
|
||||
(void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
|
||||
msg.tsp_seq = htons((in_port_t)0);
|
||||
msg.tsp_time.tv_sec = htonl((in_addr_t)tval); /* XXX: y2038 */
|
||||
msg.tsp_time.tv_usec = htonl((in_addr_t)0);
|
||||
if (connect(s, (const void *)&dest, sizeof(dest)) == -1) {
|
||||
warn("connect");
|
||||
goto bad;
|
||||
}
|
||||
if (send(s, &msg, sizeof(msg), 0) == -1) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("send");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
timed_ack = -1;
|
||||
waittime = WAITACK;
|
||||
ready.fd = s;
|
||||
ready.events = POLLIN;
|
||||
loop:
|
||||
found = poll(&ready, 1, waittime);
|
||||
|
||||
{
|
||||
socklen_t len;
|
||||
int error;
|
||||
|
||||
len = sizeof(error);
|
||||
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) == -1) {
|
||||
warn("getsockopt");
|
||||
goto bad;
|
||||
}
|
||||
if (error) {
|
||||
if (error != ECONNREFUSED) {
|
||||
errno = error;
|
||||
warn("send (delayed error)");
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (found > 0 && ready.revents & POLLIN) {
|
||||
ssize_t ret;
|
||||
|
||||
if ((ret = recv(s, &msg, sizeof(msg), 0)) == -1) {
|
||||
if (errno != ECONNREFUSED)
|
||||
warn("recv");
|
||||
goto bad;
|
||||
} else if ((size_t)ret < sizeof(msg)) {
|
||||
warnx("recv: incomplete packet");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
msg.tsp_seq = ntohs(msg.tsp_seq);
|
||||
msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
|
||||
msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
|
||||
switch (msg.tsp_type) {
|
||||
case TSP_ACK:
|
||||
timed_ack = TSP_ACK;
|
||||
waittime = WAITDATEACK;
|
||||
goto loop;
|
||||
case TSP_DATEACK:
|
||||
(void)close(s);
|
||||
return 0;
|
||||
default:
|
||||
warnx("wrong ack received from timed: %s",
|
||||
tsp_type_to_string(&msg));
|
||||
timed_ack = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (timed_ack == -1)
|
||||
warnx("can't reach time daemon, time set locally");
|
||||
|
||||
bad:
|
||||
(void)close(s);
|
||||
return 2;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
# $NetBSD: Makefile,v 1.8 1997/07/20 22:37:21 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
PROG= mkdir
|
||||
SYMLINKS= $(BINDIR)/$(PROG) /usr/bin/$(PROG)
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
@@ -1,94 +0,0 @@
|
||||
.\" $NetBSD: mkdir.1,v 1.16 2003/08/07 09:05:16 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1990, 1993
|
||||
.\" The Regents of the University of California. 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.
|
||||
.\"
|
||||
.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
|
||||
.\"
|
||||
.Dd January 25, 1994
|
||||
.Dt MKDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mkdir
|
||||
.Nd make directories
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl p
|
||||
.Op Fl m Ar mode
|
||||
.Ar directory_name ...
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
creates the directories named as operands, in the order specified,
|
||||
using mode
|
||||
.Li rwxrwxrwx (\&0777)
|
||||
as modified by the current
|
||||
.Xr umask 2 .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Pp
|
||||
.Bl -tag -width indent
|
||||
.It Fl m
|
||||
Set the file permission bits of the final created directory to
|
||||
the specified mode.
|
||||
The mode argument can be in any of the formats specified to the
|
||||
.Xr chmod 1
|
||||
utility.
|
||||
If a symbolic mode is specified, the operation characters
|
||||
.Dq +
|
||||
and
|
||||
.Dq -
|
||||
are interpreted relative to an initial mode of
|
||||
.Dq a=rwx .
|
||||
.It Fl p
|
||||
Create intermediate directories as required.
|
||||
If this option is not specified, the full path prefix of each
|
||||
operand must already exist.
|
||||
Intermediate directories are created with permission bits of
|
||||
.Li rwxrwxrwx (\&0777)
|
||||
as modified by the current umask, plus write and search
|
||||
permission for the owner.
|
||||
Do not consider it an error if the argument directory already exists.
|
||||
.El
|
||||
.Pp
|
||||
The user must have write permission in the parent directory.
|
||||
.Sh EXIT STATUS
|
||||
.Nm
|
||||
exits 0 if successful, and \*[Gt]0 if an error occurred.
|
||||
.Sh SEE ALSO
|
||||
.Xr chmod 1 ,
|
||||
.Xr rmdir 1 ,
|
||||
.Xr mkdir 2 ,
|
||||
.Xr umask 2
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
@@ -1,224 +0,0 @@
|
||||
/* $NetBSD: mkdir.c,v 1.37 2008/07/20 00:52:40 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1983, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1983, 1992, 1993\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) 1/25/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: mkdir.c,v 1.37 2008/07/20 00:52:40 lukem Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int mkpath(char *, mode_t, mode_t);
|
||||
void usage(void);
|
||||
int main(int, char *[]);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch, exitval, pflag;
|
||||
void *set;
|
||||
mode_t mode, dir_mode;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
/*
|
||||
* The default file mode is a=rwx (0777) with selected permissions
|
||||
* removed in accordance with the file mode creation mask. For
|
||||
* intermediate path name components, the mode is the default modified
|
||||
* by u+wx so that the subdirectories can always be created.
|
||||
*/
|
||||
mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~umask(0);
|
||||
dir_mode = mode | S_IWUSR | S_IXUSR;
|
||||
|
||||
pflag = 0;
|
||||
while ((ch = getopt(argc, argv, "m:p")) != -1)
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if ((set = setmode(optarg)) == NULL) {
|
||||
err(EXIT_FAILURE, "Cannot set file mode `%s'",
|
||||
optarg);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
free(set);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (*argv == NULL) {
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
for (exitval = EXIT_SUCCESS; *argv != NULL; ++argv) {
|
||||
#ifdef notdef
|
||||
char *slash;
|
||||
|
||||
/* Kernel takes care of this */
|
||||
/* Remove trailing slashes, per POSIX. */
|
||||
slash = strrchr(*argv, '\0');
|
||||
while (--slash > *argv && *slash == '/')
|
||||
*slash = '\0';
|
||||
#endif
|
||||
|
||||
if (pflag) {
|
||||
if (mkpath(*argv, mode, dir_mode) < 0)
|
||||
exitval = EXIT_FAILURE;
|
||||
} else {
|
||||
if (mkdir(*argv, mode) < 0) {
|
||||
warn("%s", *argv);
|
||||
exitval = EXIT_FAILURE;
|
||||
} else {
|
||||
/*
|
||||
* The mkdir() and umask() calls both honor
|
||||
* only the file permission bits, so if you try
|
||||
* to set a mode including the sticky, setuid,
|
||||
* setgid bits you lose them. So chmod().
|
||||
*/
|
||||
if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) != 0 &&
|
||||
chmod(*argv, mode) == -1) {
|
||||
warn("%s", *argv);
|
||||
exitval = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(exitval);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* mkpath -- create directories.
|
||||
* path - path
|
||||
* mode - file mode of terminal directory
|
||||
* dir_mode - file mode of intermediate directories
|
||||
*/
|
||||
int
|
||||
mkpath(char *path, mode_t mode, mode_t dir_mode)
|
||||
{
|
||||
struct stat sb;
|
||||
char *slash;
|
||||
int done, rv;
|
||||
|
||||
done = 0;
|
||||
slash = path;
|
||||
|
||||
for (;;) {
|
||||
slash += strspn(slash, "/");
|
||||
slash += strcspn(slash, "/");
|
||||
|
||||
done = (*slash == '\0');
|
||||
*slash = '\0';
|
||||
|
||||
rv = mkdir(path, done ? mode : dir_mode);
|
||||
if (rv < 0) {
|
||||
/*
|
||||
* Can't create; path exists or no perms.
|
||||
* stat() path to determine what's there now.
|
||||
*/
|
||||
int sverrno;
|
||||
|
||||
sverrno = errno;
|
||||
if (stat(path, &sb) < 0) {
|
||||
/* Not there; use mkdir()s error */
|
||||
errno = sverrno;
|
||||
warn("%s", path);
|
||||
return -1;
|
||||
}
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
/* Is there, but isn't a directory */
|
||||
errno = ENOTDIR;
|
||||
warn("%s", path);
|
||||
return -1;
|
||||
}
|
||||
} else if (done) {
|
||||
/*
|
||||
* Created ok, and this is the last element
|
||||
*/
|
||||
/*
|
||||
* The mkdir() and umask() calls both honor only the
|
||||
* file permission bits, so if you try to set a mode
|
||||
* including the sticky, setuid, setgid bits you lose
|
||||
* them. So chmod().
|
||||
*/
|
||||
if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) != 0 &&
|
||||
chmod(path, mode) == -1) {
|
||||
warn("%s", path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: %s [-p] [-m mode] dirname ...\n",
|
||||
getprogname());
|
||||
exit(EXIT_FAILURE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# $NetBSD: Makefile,v 1.9 1997/07/20 22:37:50 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
PROG= rm
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
207
bin/rm/rm.1
207
bin/rm/rm.1
@@ -1,207 +0,0 @@
|
||||
.\" $NetBSD: rm.1,v 1.24 2006/09/02 23:28:32 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993, 1994, 2003
|
||||
.\" The Regents of the University of California. 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.
|
||||
.\"
|
||||
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
|
||||
.\"
|
||||
.Dd August 25, 2006
|
||||
.Dt RM 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rm
|
||||
.Nd remove directory entries
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl f | Fl i
|
||||
.Op Fl dPRrvW
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility attempts to remove the non-directory type files specified on the
|
||||
command line.
|
||||
If the permissions of the file do not permit writing, and the standard
|
||||
input device is a terminal, the user is prompted (on the standard error
|
||||
output) for confirmation.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width flag
|
||||
.It Fl d
|
||||
Attempt to remove directories as well as other types of files.
|
||||
.It Fl f
|
||||
Attempt to remove the files without prompting for confirmation,
|
||||
regardless of the file's permissions.
|
||||
If the file does not exist, do not display a diagnostic message or modify
|
||||
the exit status to reflect an error.
|
||||
The
|
||||
.Fl f
|
||||
option overrides any previous
|
||||
.Fl i
|
||||
options.
|
||||
.It Fl i
|
||||
Request confirmation before attempting to remove each file, regardless of
|
||||
the file's permissions, or whether or not the standard input device is a
|
||||
terminal.
|
||||
The
|
||||
.Fl i
|
||||
option overrides any previous
|
||||
.Fl f
|
||||
options.
|
||||
.It Fl P
|
||||
Overwrite regular files before deleting them.
|
||||
Files are overwritten three times, first with the byte pattern 0xff,
|
||||
then 0x00, and then with random data, before they are deleted.
|
||||
Some care is taken to ensure that the data are actually written to
|
||||
disk, but this cannot be guaranteed, even on traditional filesystems;
|
||||
on log-structured filesystems or if any block-journaling scheme is
|
||||
in use, this option is completely useless.
|
||||
If the file cannot be
|
||||
overwritten, it will not be removed.
|
||||
.It Fl R
|
||||
Attempt to remove the file hierarchy rooted in each file argument.
|
||||
The
|
||||
.Fl R
|
||||
option implies the
|
||||
.Fl d
|
||||
option.
|
||||
If the
|
||||
.Fl i
|
||||
option is specified, the user is prompted for confirmation before
|
||||
each directory's contents are processed (as well as before the attempt
|
||||
is made to remove the directory).
|
||||
If the user does not respond affirmatively, the file hierarchy rooted in
|
||||
that directory is skipped.
|
||||
.Pp
|
||||
.It Fl r
|
||||
Equivalent to
|
||||
.Fl R .
|
||||
.It Fl v
|
||||
Cause
|
||||
.Nm
|
||||
to be verbose, showing files as they are processed.
|
||||
.It Fl W
|
||||
Attempts to undelete the named files.
|
||||
Currently, this option can only be used to recover
|
||||
files covered by whiteouts.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility removes symbolic links, not the files referenced by the links.
|
||||
.Pp
|
||||
It is an error to attempt to remove the files ``.'' and ``..''.
|
||||
.Sh EXIT STATUS
|
||||
The
|
||||
.Nm
|
||||
utility exits 0 if all of the named files or file hierarchies were removed,
|
||||
or if the
|
||||
.Fl f
|
||||
option was specified and all of the existing files or file hierarchies were
|
||||
removed.
|
||||
If an error occurs,
|
||||
.Nm
|
||||
exits with a value \*[Gt]0.
|
||||
.Sh EXAMPLES
|
||||
.Nm
|
||||
uses
|
||||
.Xr getopt 3
|
||||
standard argument processing.
|
||||
Removing filenames that begin with a dash
|
||||
.Pq e.g., Ar -file
|
||||
in the current directory which might otherwise be taken as option flags to
|
||||
.Nm
|
||||
can be accomplished as follows:
|
||||
.Pp
|
||||
.Ic "rm -- -file"
|
||||
.Pp
|
||||
or
|
||||
.Pp
|
||||
.Ic "rm ./-file"
|
||||
.Sh SEE ALSO
|
||||
.Xr rmdir 1 ,
|
||||
.Xr undelete 2 ,
|
||||
.Xr unlink 2 ,
|
||||
.Xr fts 3 ,
|
||||
.Xr getopt 3 ,
|
||||
.Xr symlink 7
|
||||
.Sh BUGS
|
||||
The
|
||||
.Fl P
|
||||
option assumes that the underlying file system is a fixed-block file
|
||||
system.
|
||||
FFS is a fixed-block file system, LFS is not.
|
||||
In addition, only regular files are overwritten, other types of files
|
||||
are not.
|
||||
Recent research indicates that as many as 35 overwrite passes with
|
||||
carefully chosen data patterns may be necessary to actually prevent
|
||||
recovery of data from a magnetic disk.
|
||||
Thus the
|
||||
.Fl P
|
||||
option is likely both insufficient for its design purpose and far
|
||||
too costly for default operation.
|
||||
However, it will at least prevent the recovery of data from FFS
|
||||
volumes with
|
||||
.Xr fsdb 8 .
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Nm
|
||||
utility differs from historical implementations in that the
|
||||
.Fl f
|
||||
option only masks attempts to remove non-existent files instead of
|
||||
masking a large variety of errors.
|
||||
.Pp
|
||||
Also, historical
|
||||
.Bx
|
||||
implementations prompted on the standard output,
|
||||
not the standard error output.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
The
|
||||
.Fl v
|
||||
option is an extension.
|
||||
.Pp
|
||||
The
|
||||
.Fl P
|
||||
option attempts to conform to U.S. DoD 5220-22.M, "National Industrial
|
||||
Security Program Operating Manual" ("NISPOM") as updated by Change
|
||||
2 and the July 23, 2003 "Clearing \*[Am] Sanitization Matrix".
|
||||
However, unlike earlier revisions of NISPOM, the 2003 matrix imposes
|
||||
requirements which make it clear that the standard does not and
|
||||
can not apply to the erasure of individual files, in particular
|
||||
requirements relating to spare sector management for an entire
|
||||
magnetic disk.
|
||||
.Em Because these requirements are not met, the
|
||||
.Fl P
|
||||
.Em option does not conform to the standard .
|
||||
605
bin/rm/rm.c
605
bin/rm/rm.c
@@ -1,605 +0,0 @@
|
||||
/* $NetBSD: rm.c,v 1.50 2011/08/29 14:48:46 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994, 2003
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rm.c 8.8 (Berkeley) 4/27/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: rm.c,v 1.50 2011/08/29 14:48:46 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fts.h>
|
||||
#include <grp.h>
|
||||
#include <locale.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag;
|
||||
|
||||
static int check(char *, char *, struct stat *);
|
||||
static void checkdot(char **);
|
||||
static void rm_file(char **);
|
||||
static int rm_overwrite(char *, struct stat *);
|
||||
static void rm_tree(char **);
|
||||
__dead static void usage(void);
|
||||
|
||||
#ifdef __minix
|
||||
# ifndef O_SYNC
|
||||
# define O_SYNC 0
|
||||
# endif
|
||||
# ifndef O_RSYNC
|
||||
# define O_RSYNC 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For the sake of the `-f' flag, check whether an error number indicates the
|
||||
* failure of an operation due to an non-existent file, either per se (ENOENT)
|
||||
* or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR).
|
||||
*/
|
||||
#define NONEXISTENT(x) \
|
||||
((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR)
|
||||
|
||||
/*
|
||||
* rm --
|
||||
* This rm is different from historic rm's, but is expected to match
|
||||
* POSIX 1003.2 behavior. The most visible difference is that -f
|
||||
* has two specific effects now, ignore non-existent files and force
|
||||
* file removal.
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch, rflag;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
Pflag = rflag = 0;
|
||||
while ((ch = getopt(argc, argv, "dfiPRrvW")) != -1)
|
||||
switch (ch) {
|
||||
case 'd':
|
||||
dflag = 1;
|
||||
break;
|
||||
case 'f':
|
||||
fflag = 1;
|
||||
iflag = 0;
|
||||
break;
|
||||
case 'i':
|
||||
fflag = 0;
|
||||
iflag = 1;
|
||||
break;
|
||||
case 'P':
|
||||
Pflag = 1;
|
||||
break;
|
||||
case 'R':
|
||||
case 'r': /* Compatibility. */
|
||||
rflag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
case 'W':
|
||||
Wflag = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
if (fflag)
|
||||
return 0;
|
||||
usage();
|
||||
}
|
||||
|
||||
checkdot(argv);
|
||||
|
||||
if (*argv) {
|
||||
stdin_ok = isatty(STDIN_FILENO);
|
||||
|
||||
if (rflag)
|
||||
rm_tree(argv);
|
||||
else
|
||||
rm_file(argv);
|
||||
}
|
||||
|
||||
exit(eval);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static void
|
||||
rm_tree(char **argv)
|
||||
{
|
||||
FTS *fts;
|
||||
FTSENT *p;
|
||||
int flags, needstat, rval;
|
||||
|
||||
/*
|
||||
* Remove a file hierarchy. If forcing removal (-f), or interactive
|
||||
* (-i) or can't ask anyway (stdin_ok), don't stat the file.
|
||||
*/
|
||||
needstat = !fflag && !iflag && stdin_ok;
|
||||
|
||||
/*
|
||||
* If the -i option is specified, the user can skip on the pre-order
|
||||
* visit. The fts_number field flags skipped directories.
|
||||
*/
|
||||
#define SKIPPED 1
|
||||
|
||||
flags = FTS_PHYSICAL;
|
||||
if (!needstat)
|
||||
flags |= FTS_NOSTAT;
|
||||
#ifndef __minix
|
||||
if (Wflag)
|
||||
flags |= FTS_WHITEOUT;
|
||||
#endif
|
||||
if ((fts = fts_open(argv, flags, NULL)) == NULL)
|
||||
err(1, "fts_open failed");
|
||||
while ((p = fts_read(fts)) != NULL) {
|
||||
|
||||
switch (p->fts_info) {
|
||||
case FTS_DNR:
|
||||
if (!fflag || p->fts_errno != ENOENT) {
|
||||
warnx("%s: %s", p->fts_path,
|
||||
strerror(p->fts_errno));
|
||||
eval = 1;
|
||||
}
|
||||
continue;
|
||||
case FTS_ERR:
|
||||
errx(EXIT_FAILURE, "%s: %s", p->fts_path,
|
||||
strerror(p->fts_errno));
|
||||
/* NOTREACHED */
|
||||
case FTS_NS:
|
||||
/*
|
||||
* FTS_NS: assume that if can't stat the file, it
|
||||
* can't be unlinked.
|
||||
*/
|
||||
if (fflag && NONEXISTENT(p->fts_errno))
|
||||
continue;
|
||||
if (needstat) {
|
||||
warnx("%s: %s", p->fts_path,
|
||||
strerror(p->fts_errno));
|
||||
eval = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case FTS_D:
|
||||
/* Pre-order: give user chance to skip. */
|
||||
if (!fflag && !check(p->fts_path, p->fts_accpath,
|
||||
p->fts_statp)) {
|
||||
(void)fts_set(fts, p, FTS_SKIP);
|
||||
p->fts_number = SKIPPED;
|
||||
}
|
||||
continue;
|
||||
case FTS_DP:
|
||||
/* Post-order: see if user skipped. */
|
||||
if (p->fts_number == SKIPPED)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
if (!fflag &&
|
||||
!check(p->fts_path, p->fts_accpath, p->fts_statp))
|
||||
continue;
|
||||
}
|
||||
|
||||
rval = 0;
|
||||
/*
|
||||
* If we can't read or search the directory, may still be
|
||||
* able to remove it. Don't print out the un{read,search}able
|
||||
* message unless the remove fails.
|
||||
*/
|
||||
switch (p->fts_info) {
|
||||
case FTS_DP:
|
||||
case FTS_DNR:
|
||||
rval = rmdir(p->fts_accpath);
|
||||
if (rval != 0 && fflag && errno == ENOENT)
|
||||
continue;
|
||||
break;
|
||||
|
||||
#ifndef __minix
|
||||
case FTS_W:
|
||||
rval = undelete(p->fts_accpath);
|
||||
if (rval != 0 && fflag && errno == ENOENT)
|
||||
continue;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
if (Pflag) {
|
||||
if (rm_overwrite(p->fts_accpath, NULL))
|
||||
continue;
|
||||
}
|
||||
rval = unlink(p->fts_accpath);
|
||||
if (rval != 0 && fflag && NONEXISTENT(errno))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (rval != 0) {
|
||||
warn("%s", p->fts_path);
|
||||
eval = 1;
|
||||
} else if (vflag)
|
||||
(void)printf("%s\n", p->fts_path);
|
||||
}
|
||||
if (errno)
|
||||
err(1, "fts_read");
|
||||
fts_close(fts);
|
||||
}
|
||||
|
||||
static void
|
||||
rm_file(char **argv)
|
||||
{
|
||||
struct stat sb;
|
||||
int rval;
|
||||
char *f;
|
||||
|
||||
/*
|
||||
* Remove a file. POSIX 1003.2 states that, by default, attempting
|
||||
* to remove a directory is an error, so must always stat the file.
|
||||
*/
|
||||
while ((f = *argv++) != NULL) {
|
||||
/* Assume if can't stat the file, can't unlink it. */
|
||||
if (lstat(f, &sb)) {
|
||||
if (Wflag) {
|
||||
#ifdef __minix
|
||||
sb.st_mode = S_IWUSR|S_IRUSR;
|
||||
#else
|
||||
sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
|
||||
#endif
|
||||
} else {
|
||||
if (!fflag || !NONEXISTENT(errno)) {
|
||||
warn("%s", f);
|
||||
eval = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else if (Wflag) {
|
||||
warnx("%s: %s", f, strerror(EEXIST));
|
||||
eval = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(sb.st_mode) && !dflag) {
|
||||
warnx("%s: is a directory", f);
|
||||
eval = 1;
|
||||
continue;
|
||||
}
|
||||
#ifndef __minix
|
||||
if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
|
||||
#else
|
||||
if (!fflag && !check(f, f, &sb))
|
||||
#endif
|
||||
continue;
|
||||
#ifndef __minix
|
||||
if (S_ISWHT(sb.st_mode))
|
||||
rval = undelete(f);
|
||||
else
|
||||
#endif
|
||||
if (S_ISDIR(sb.st_mode))
|
||||
rval = rmdir(f);
|
||||
else {
|
||||
if (Pflag) {
|
||||
if (rm_overwrite(f, &sb))
|
||||
continue;
|
||||
}
|
||||
rval = unlink(f);
|
||||
}
|
||||
if (rval && (!fflag || !NONEXISTENT(errno))) {
|
||||
warn("%s", f);
|
||||
eval = 1;
|
||||
}
|
||||
if (vflag && rval == 0)
|
||||
(void)printf("%s\n", f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rm_overwrite --
|
||||
* Overwrite the file 3 times with varying bit patterns.
|
||||
*
|
||||
* This is an expensive way to keep people from recovering files from your
|
||||
* non-snapshotted FFS filesystems using fsdb(8). Really. No more. Only
|
||||
* regular files are deleted, directories (and therefore names) will remain.
|
||||
* Also, this assumes a fixed-block file system (like FFS, or a V7 or a
|
||||
* System V file system). In a logging file system, you'll have to have
|
||||
* kernel support.
|
||||
*
|
||||
* A note on standards: U.S. DoD 5220.22-M "National Industrial Security
|
||||
* Program Operating Manual" ("NISPOM") is often cited as a reference
|
||||
* for clearing and sanitizing magnetic media. In fact, a matrix of
|
||||
* "clearing" and "sanitization" methods for various media was given in
|
||||
* Chapter 8 of the original 1995 version of NISPOM. However, that
|
||||
* matrix was *removed from the document* when Chapter 8 was rewritten
|
||||
* in Change 2 to the document in 2001. Recently, the Defense Security
|
||||
* Service has made a revised clearing and sanitization matrix available
|
||||
* in Microsoft Word format on the DSS web site. The standardization
|
||||
* status of this matrix is unclear. Furthermore, one must be very
|
||||
* careful when referring to this matrix: it is intended for the "clearing"
|
||||
* prior to reuse or "sanitization" prior to disposal of *entire media*,
|
||||
* not individual files and the only non-physically-destructive method of
|
||||
* "sanitization" that is permitted for magnetic disks of any kind is
|
||||
* specifically noted to be prohibited for media that have contained
|
||||
* Top Secret data.
|
||||
*
|
||||
* It is impossible to actually conform to the exact procedure given in
|
||||
* the matrix if one is overwriting a file, not an entire disk, because
|
||||
* the procedure requires examination and comparison of the disk's defect
|
||||
* lists. Any program that claims to securely erase *files* while
|
||||
* conforming to the standard, then, is not correct. We do as much of
|
||||
* what the standard requires as can actually be done when erasing a
|
||||
* file, rather than an entire disk; but that does not make us conformant.
|
||||
*
|
||||
* Furthermore, the presence of track caches, disk and controller write
|
||||
* caches, and so forth make it extremely difficult to ensure that data
|
||||
* have actually been written to the disk, particularly when one tries
|
||||
* to repeatedly overwrite the same sectors in quick succession. We call
|
||||
* fsync(), but controllers with nonvolatile cache, as well as IDE disks
|
||||
* that just plain lie about the stable storage of data, will defeat this.
|
||||
*
|
||||
* Finally, widely respected research suggests that the given procedure
|
||||
* is nowhere near sufficient to prevent the recovery of data using special
|
||||
* forensic equipment and techniques that are well-known. This is
|
||||
* presumably one reason that the matrix requires physical media destruction,
|
||||
* rather than any technique of the sort attempted here, for secret data.
|
||||
*
|
||||
* Caveat Emptor.
|
||||
*
|
||||
* rm_overwrite will return 0 on success.
|
||||
*/
|
||||
|
||||
static int
|
||||
rm_overwrite(char *file, struct stat *sbp)
|
||||
{
|
||||
struct stat sb;
|
||||
int fd, randint;
|
||||
char randchar;
|
||||
|
||||
fd = -1;
|
||||
if (sbp == NULL) {
|
||||
if (lstat(file, &sb))
|
||||
goto err;
|
||||
sbp = &sb;
|
||||
}
|
||||
if (!S_ISREG(sbp->st_mode))
|
||||
return 0;
|
||||
|
||||
/* flags to try to defeat hidden caching by forcing seeks */
|
||||
if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC, 0)) == -1)
|
||||
goto err;
|
||||
|
||||
#define RAND_BYTES 1
|
||||
#define THIS_BYTE 0
|
||||
|
||||
#define WRITE_PASS(mode, byte) do { \
|
||||
off_t len; \
|
||||
size_t wlen, i; \
|
||||
char buf[8 * 1024]; \
|
||||
\
|
||||
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \
|
||||
goto err; \
|
||||
\
|
||||
if (mode == THIS_BYTE) \
|
||||
memset(buf, byte, sizeof(buf)); \
|
||||
for (len = sbp->st_size; len > 0; len -= wlen) { \
|
||||
if (mode == RAND_BYTES) { \
|
||||
for (i = 0; i < sizeof(buf); \
|
||||
i+= sizeof(u_int32_t)) \
|
||||
*(int *)(buf + i) = arc4random(); \
|
||||
} \
|
||||
wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
|
||||
if ((size_t)write(fd, buf, wlen) != wlen) \
|
||||
goto err; \
|
||||
} \
|
||||
sync(); /* another poke at hidden caches */ \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
#define READ_PASS(byte) do { \
|
||||
off_t len; \
|
||||
size_t rlen; \
|
||||
char pattern[8 * 1024]; \
|
||||
char buf[8 * 1024]; \
|
||||
\
|
||||
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET)) \
|
||||
goto err; \
|
||||
\
|
||||
memset(pattern, byte, sizeof(pattern)); \
|
||||
for(len = sbp->st_size; len > 0; len -= rlen) { \
|
||||
rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
|
||||
if((size_t)read(fd, buf, rlen) != rlen) \
|
||||
goto err; \
|
||||
if(memcmp(buf, pattern, rlen)) \
|
||||
goto err; \
|
||||
} \
|
||||
sync(); /* another poke at hidden caches */ \
|
||||
} while (/* CONSTCOND */ 0)
|
||||
|
||||
/*
|
||||
* DSS sanitization matrix "clear" for magnetic disks:
|
||||
* option 'c' "Overwrite all addressable locations with a single
|
||||
* character."
|
||||
*/
|
||||
randint = arc4random();
|
||||
randchar = *(char *)&randint;
|
||||
WRITE_PASS(THIS_BYTE, randchar);
|
||||
|
||||
/*
|
||||
* DSS sanitization matrix "sanitize" for magnetic disks:
|
||||
* option 'd', sub 2 "Overwrite all addressable locations with a
|
||||
* character, then its complement. Verify "complement" character
|
||||
* was written successfully to all addressable locations, then
|
||||
* overwrite all addressable locations with random characters; or
|
||||
* verify third overwrite of random characters." The rest of the
|
||||
* text in d-sub-2 specifies requirements for overwriting spared
|
||||
* sectors; we cannot conform to it when erasing only a file, thus
|
||||
* we do not conform to the standard.
|
||||
*/
|
||||
|
||||
/* 1. "a character" */
|
||||
WRITE_PASS(THIS_BYTE, 0xff);
|
||||
|
||||
/* 2. "its complement" */
|
||||
WRITE_PASS(THIS_BYTE, 0x00);
|
||||
|
||||
/* 3. "Verify 'complement' character" */
|
||||
READ_PASS(0x00);
|
||||
|
||||
/* 4. "overwrite all addressable locations with random characters" */
|
||||
|
||||
WRITE_PASS(RAND_BYTES, 0x00);
|
||||
|
||||
/*
|
||||
* As the file might be huge, and we note that this revision of
|
||||
* the matrix says "random characters", not "a random character"
|
||||
* as the original did, we do not verify the random-character
|
||||
* write; the "or" in the standard allows this.
|
||||
*/
|
||||
|
||||
if (close(fd) == -1) {
|
||||
fd = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err: eval = 1;
|
||||
warn("%s", file);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
check(char *path, char *name, struct stat *sp)
|
||||
{
|
||||
int ch, first;
|
||||
char modep[15];
|
||||
|
||||
/* Check -i first. */
|
||||
if (iflag)
|
||||
(void)fprintf(stderr, "remove '%s'? ", path);
|
||||
else {
|
||||
/*
|
||||
* If it's not a symbolic link and it's unwritable and we're
|
||||
* talking to a terminal, ask. Symbolic links are excluded
|
||||
* because their permissions are meaningless. Check stdin_ok
|
||||
* first because we may not have stat'ed the file.
|
||||
*/
|
||||
if (!stdin_ok || S_ISLNK(sp->st_mode) ||
|
||||
!(access(name, W_OK) && (errno != ETXTBSY)))
|
||||
return (1);
|
||||
strmode(sp->st_mode, modep);
|
||||
if (Pflag) {
|
||||
warnx(
|
||||
"%s: -P was specified but file could not"
|
||||
" be overwritten", path);
|
||||
return 0;
|
||||
}
|
||||
(void)fprintf(stderr, "override %s%s%s:%s for '%s'? ",
|
||||
modep + 1, modep[9] == ' ' ? "" : " ",
|
||||
user_from_uid(sp->st_uid, 0),
|
||||
group_from_gid(sp->st_gid, 0), path);
|
||||
}
|
||||
(void)fflush(stderr);
|
||||
|
||||
first = ch = getchar();
|
||||
while (ch != '\n' && ch != EOF)
|
||||
ch = getchar();
|
||||
return (first == 'y' || first == 'Y');
|
||||
}
|
||||
|
||||
/*
|
||||
* POSIX.2 requires that if "." or ".." are specified as the basename
|
||||
* portion of an operand, a diagnostic message be written to standard
|
||||
* error and nothing more be done with such operands.
|
||||
*
|
||||
* Since POSIX.2 defines basename as the final portion of a path after
|
||||
* trailing slashes have been removed, we'll remove them here.
|
||||
*/
|
||||
#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
|
||||
static void
|
||||
checkdot(char **argv)
|
||||
{
|
||||
char *p, **save, **t;
|
||||
int complained;
|
||||
|
||||
complained = 0;
|
||||
for (t = argv; *t;) {
|
||||
/* strip trailing slashes */
|
||||
p = strrchr(*t, '\0');
|
||||
while (--p > *t && *p == '/')
|
||||
*p = '\0';
|
||||
|
||||
/* extract basename */
|
||||
if ((p = strrchr(*t, '/')) != NULL)
|
||||
++p;
|
||||
else
|
||||
p = *t;
|
||||
|
||||
if (ISDOT(p)) {
|
||||
if (!complained++)
|
||||
warnx("\".\" and \"..\" may not be removed");
|
||||
eval = 1;
|
||||
for (save = t; (t[0] = t[1]) != NULL; ++t)
|
||||
continue;
|
||||
t = save;
|
||||
} else
|
||||
++t;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvW] file ...\n",
|
||||
getprogname());
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# $NetBSD: Makefile,v 1.8 1997/07/20 22:37:52 christos Exp $
|
||||
# @(#)Makefile 8.1 (Berkeley) 5/31/93
|
||||
|
||||
PROG= rmdir
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
@@ -1,90 +0,0 @@
|
||||
.\" $NetBSD: rmdir.1,v 1.15 2003/08/07 09:05:29 agc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. 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.
|
||||
.\"
|
||||
.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
|
||||
.\"
|
||||
.Dd May 31, 1993
|
||||
.Dt RMDIR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rmdir
|
||||
.Nd remove directories
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl p
|
||||
.Ar directory ...
|
||||
.Sh DESCRIPTION
|
||||
The rmdir utility removes the directory entry specified by
|
||||
each
|
||||
.Ar directory
|
||||
argument, provided it is empty.
|
||||
.Pp
|
||||
Arguments are processed in the order given.
|
||||
In order to remove both a parent directory and a subdirectory
|
||||
of that parent, the subdirectory
|
||||
must be specified first so the parent directory
|
||||
is empty when
|
||||
.Nm
|
||||
tries to remove it.
|
||||
.Pp
|
||||
The following option is available:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl p
|
||||
Each
|
||||
.Ar directory
|
||||
argument is treated as a pathname of which all
|
||||
components will be removed, if they are empty,
|
||||
starting with the last most component.
|
||||
(See
|
||||
.Xr rm 1
|
||||
for fully non-discriminant recursive removal.)
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
The
|
||||
.Nm
|
||||
utility exits with one of the following values:
|
||||
.Bl -tag -width Ds
|
||||
.It Li \&0
|
||||
Each directory entry specified by a dir operand
|
||||
referred to an empty directory and was removed
|
||||
successfully.
|
||||
.It Li \&\*[Gt]\&0
|
||||
An error occurred.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr rm 1
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is expected to be
|
||||
.St -p1003.2
|
||||
compatible.
|
||||
@@ -1,121 +0,0 @@
|
||||
/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
|
||||
The Regents of the University of California. All rights reserved.");
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)rmdir.c 8.3 (Berkeley) 4/2/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int rm_path(char *);
|
||||
__dead static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch, errors, pflag;
|
||||
|
||||
setprogname(argv[0]);
|
||||
(void)setlocale(LC_ALL, "");
|
||||
|
||||
pflag = 0;
|
||||
while ((ch = getopt(argc, argv, "p")) != -1)
|
||||
switch(ch) {
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0)
|
||||
usage();
|
||||
|
||||
for (errors = 0; *argv; argv++) {
|
||||
/* We rely on the kernel to ignore trailing '/' characters. */
|
||||
if (rmdir(*argv) < 0) {
|
||||
warn("%s", *argv);
|
||||
errors = 1;
|
||||
} else if (pflag)
|
||||
errors |= rm_path(*argv);
|
||||
}
|
||||
|
||||
exit(errors);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
rm_path(char *path)
|
||||
{
|
||||
char *p;
|
||||
|
||||
while ((p = strrchr(path, '/')) != NULL) {
|
||||
*p = 0;
|
||||
if (p[1] == 0)
|
||||
/* Ignore trailing '/' on deleted name */
|
||||
continue;
|
||||
|
||||
if (rmdir(path) < 0) {
|
||||
warn("%s", path);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname());
|
||||
exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
116
boot/Makefile
Executable file
116
boot/Makefile
Executable file
@@ -0,0 +1,116 @@
|
||||
# Makefile for the boot monitor package.
|
||||
|
||||
SYS = ..
|
||||
|
||||
CC = exec cc
|
||||
CC86 = exec cc -mi86 -Was-ncc
|
||||
CFLAGS = -I$(SYS)
|
||||
LIBS = -lsys
|
||||
LD = $(CC) -s -.o
|
||||
LD86 = $(CC86) -.o
|
||||
BIN = /usr/bin
|
||||
MDEC = /usr/mdec
|
||||
|
||||
all: bootblock boot edparams masterboot jumpboot installboot addaout
|
||||
dos: boot.com mkfile.com
|
||||
|
||||
bootblock: bootblock.s
|
||||
$(LD86) -com -o $@ bootblock.s
|
||||
|
||||
masterboot: masterboot.s
|
||||
$(LD86) -com -o $@ masterboot.s
|
||||
|
||||
jumpboot: jumpboot.s
|
||||
$(LD86) -com -o $@ jumpboot.s
|
||||
|
||||
boot.o: boot.c
|
||||
$(CC86) $(CFLAGS) -c boot.c
|
||||
|
||||
bootimage.o: bootimage.c
|
||||
$(CC86) $(CFLAGS) -c bootimage.c
|
||||
|
||||
rawfs86.o: rawfs.c rawfs.o
|
||||
ln -f rawfs.c rawfs86.c
|
||||
$(CC86) $(CFLAGS) -c rawfs86.c
|
||||
rm rawfs86.c
|
||||
-cmp -s rawfs.o rawfs86.o && ln -f rawfs.o rawfs86.o
|
||||
|
||||
boot: boothead.s boot.o bootimage.o rawfs86.o
|
||||
$(LD86) -o $@ \
|
||||
boothead.s boot.o bootimage.o rawfs86.o $(LIBS)
|
||||
install -S 8kb boot
|
||||
|
||||
edparams.o: boot.c
|
||||
ln -f boot.c edparams.c
|
||||
$(CC) $(CFLAGS) -DUNIX -c edparams.c
|
||||
rm edparams.c
|
||||
|
||||
edparams: edparams.o rawfs.o
|
||||
$(CC) $(CFLAGS) $(STRIP) -o $@ edparams.o rawfs.o
|
||||
install -S 16kw edparams
|
||||
|
||||
dosboot.o: boot.c
|
||||
$(CC86) $(CFLAGS) -DDOS -o $@ -c boot.c
|
||||
|
||||
doshead.o: doshead.s
|
||||
$(CC) -mi386 -o $@ -c doshead.s
|
||||
|
||||
dosboot: doshead.o dosboot.o bootimage.o rawfs86.o
|
||||
$(LD86) -com -o $@ \
|
||||
doshead.o dosboot.o bootimage.o rawfs86.o $(LIBS)
|
||||
|
||||
boot.com: dosboot
|
||||
./a.out2com dosboot boot.com
|
||||
|
||||
mkfile: mkfhead.s mkfile.c
|
||||
$(LD) -.o -mi86 -com -o $@ mkfhead.s mkfile.c $(LIBS)
|
||||
|
||||
mkfile.com: mkfile
|
||||
./a.out2com mkfile mkfile.com
|
||||
|
||||
installboot: installboot.o rawfs.o
|
||||
$(CC) $(STRIP) -o installboot installboot.o rawfs.o
|
||||
install -S 6kw installboot
|
||||
|
||||
addaout: addaout.o
|
||||
$(CC) -o addaout addaout.o
|
||||
|
||||
installboot.o bootimage.o: image.h
|
||||
boot.o bootimage.o dosboot.o edparams.o: boot.h
|
||||
rawfs.o rawfs86.o installboot.o boot.o bootimage.o: rawfs.h
|
||||
|
||||
install: $(MDEC)/bootblock $(MDEC)/boot $(MDEC)/masterboot \
|
||||
$(MDEC)/jumpboot $(BIN)/installboot $(BIN)/edparams
|
||||
dosinstall: $(MDEC)/boot.com $(MDEC)/mkfile.com
|
||||
|
||||
$(MDEC)/bootblock: bootblock
|
||||
install -cs -o bin -m 644 $? $@
|
||||
|
||||
$(MDEC)/boot: boot
|
||||
install -cs -o bin -m 644 $? $@
|
||||
|
||||
$(MDEC)/boot.com: boot.com
|
||||
install -c -m 644 $? $@
|
||||
|
||||
$(MDEC)/mkfile.com: mkfile.com
|
||||
install -c -m 644 $? $@
|
||||
|
||||
$(MDEC)/masterboot: masterboot
|
||||
install -cs -o bin -m 644 $? $@
|
||||
|
||||
$(MDEC)/jumpboot: jumpboot
|
||||
install -cs -o bin -m 644 $? $@
|
||||
|
||||
$(BIN)/installboot: installboot
|
||||
install -cs -o bin $? $@
|
||||
|
||||
$(BIN)/addaout: addaout
|
||||
install -cs -o bin $? $@
|
||||
|
||||
$(BIN)/edparams: edparams
|
||||
install -cs -o bin $? $@
|
||||
|
||||
clean:
|
||||
rm -f *.bak *.o
|
||||
rm -f bootblock addaout installboot boot masterboot jumpboot edparams
|
||||
rm -f dosboot boot.com mkfile mkfile.com
|
||||
25
boot/a.out2com
Executable file
25
boot/a.out2com
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# a.out2com - Minix a.out to DOS .COM Author: Kees J. Bot
|
||||
# 17 Jun 1995
|
||||
# Transform a Minix a.out to the COM format of MS-DOS,
|
||||
# the executable must be common I&D with 256 scratch bytes at the start of
|
||||
# the text segment to make space for the Program Segment Prefix. The Minix
|
||||
# a.out header and these 256 bytes are removed to make a COM file.
|
||||
|
||||
case $# in
|
||||
2) aout="$1"
|
||||
com="$2"
|
||||
;;
|
||||
*) echo "Usage: $0 <a.out> <dos.com>" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
size "$aout" >/dev/null || exit
|
||||
set `size "$aout" | sed 1d`
|
||||
count=`expr \( $1 + $2 - 256 + 31 \) / 32`
|
||||
|
||||
exec dd if="$aout" of="$com" bs=32 skip=9 count=$count conv=silent
|
||||
|
||||
#
|
||||
# $PchId: a.out2com,v 1.3 1998/08/01 09:13:01 philip Exp $
|
||||
128
boot/addaout.c
Normal file
128
boot/addaout.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/* A small utility to append an a.out header to an arbitrary file. This allows
|
||||
* inclusion of arbitrary data in the boot image, so that it is magically
|
||||
* loaded as a RAM disk. The a.out header is structured as follows:
|
||||
*
|
||||
* a_flags: A_IMG to indicate this is not an executable
|
||||
*
|
||||
* Created: April 2005, Jorrit N. Herder
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <a.out.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define INPUT_FILE 1
|
||||
#define OUTPUT_FILE 2
|
||||
|
||||
/* Report problems. */
|
||||
void report(char *problem, char *message)
|
||||
{
|
||||
fprintf(stderr, "%s:\n", problem);
|
||||
fprintf(stderr, " %s\n\n", message);
|
||||
}
|
||||
|
||||
|
||||
int copy_data(int srcfd, int dstfd)
|
||||
{
|
||||
char buf[8192];
|
||||
ssize_t n;
|
||||
int total=0;
|
||||
|
||||
/* Copy the little bytes themselves. (Source from cp.c). */
|
||||
while ((n= read(srcfd, buf, sizeof(buf))) > 0) {
|
||||
char *bp = buf;
|
||||
ssize_t r;
|
||||
|
||||
while (n > 0 && (r= write(dstfd, bp, n)) > 0) {
|
||||
bp += r;
|
||||
n -= r;
|
||||
total += r;
|
||||
}
|
||||
if (r <= 0) {
|
||||
if (r == 0) {
|
||||
fprintf(stderr, "Warning: EOF writing to output file.\n");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(total);
|
||||
}
|
||||
|
||||
|
||||
/* Main program. */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct exec aout;
|
||||
struct stat stin;
|
||||
int fdin, fdout;
|
||||
char * bp;
|
||||
int n,r;
|
||||
int total_size=0;
|
||||
int result;
|
||||
|
||||
/* Check if command line arguments are present, or print usage. */
|
||||
if (argc!=3) {
|
||||
printf("Invalid arguments. Usage:\n");
|
||||
printf(" %s <input_file> <output_file>\n",argv[0]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Check if we can open the input and output file. */
|
||||
if (stat(argv[INPUT_FILE], &stin) != 0) {
|
||||
report("Couldn't get status of input file", strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
if ((fdin = open(argv[INPUT_FILE], O_RDONLY)) < 0) {
|
||||
report("Couldn't open input file", strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
if ((fdout = open(argv[OUTPUT_FILE], O_WRONLY|O_CREAT|O_TRUNC,
|
||||
stin.st_mode & 0777)) < 0) {
|
||||
report("Couldn't open output file", strerror(errno));
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Copy input file to output file, but leave space for a.out header. */
|
||||
lseek(fdout, sizeof(aout), SEEK_SET);
|
||||
total_size = copy_data(fdin, fdout);
|
||||
if (total_size < 0) {
|
||||
report("Aborted", "Output file may be truncated.");
|
||||
return(1);
|
||||
} else if (total_size == 0) {
|
||||
report("Aborted without prepending header", "No data in input file.");
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Build a.out header and write to output file. */
|
||||
memset(&aout, 0, sizeof(struct exec));
|
||||
aout.a_magic[0] = A_MAGIC0;
|
||||
aout.a_magic[1] = A_MAGIC1;
|
||||
aout.a_flags |= A_IMG;
|
||||
aout.a_hdrlen = sizeof(aout);
|
||||
aout.a_text = 0;
|
||||
aout.a_data = total_size;
|
||||
aout.a_bss = 0;
|
||||
aout.a_total = aout.a_hdrlen + aout.a_data;
|
||||
|
||||
bp = (char *) &aout;
|
||||
n = sizeof(aout);
|
||||
lseek(fdout, 0, SEEK_SET);
|
||||
while (n > 0 && (r= write(fdout, bp, n)) > 0) {
|
||||
bp += r;
|
||||
n -= r;
|
||||
}
|
||||
|
||||
printf("Prepended data file (%u bytes) with a.out header (%u bytes).\n",
|
||||
total_size, sizeof(aout));
|
||||
printf("Done.\n");
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
1957
boot/boot.c
Executable file
1957
boot/boot.c
Executable file
File diff suppressed because it is too large
Load Diff
212
boot/boot.h
Executable file
212
boot/boot.h
Executable file
@@ -0,0 +1,212 @@
|
||||
/* boot.h - Info between different parts of boot. Author: Kees J. Bot
|
||||
*/
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
/* Constants describing the metal: */
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
#define SECTOR_SHIFT 9
|
||||
#define RATIO(b) ((b) / SECTOR_SIZE)
|
||||
|
||||
#define PARAMSEC 1 /* Sector containing boot parameters. */
|
||||
|
||||
#define DSKBASE 0x1E /* Floppy disk parameter vector. */
|
||||
#define DSKPARSIZE 11 /* There are this many bytes of parameters. */
|
||||
|
||||
#define ESC '\33' /* Escape key. */
|
||||
|
||||
#define HEADERPOS 0x00600L /* Place for an array of struct exec's. */
|
||||
|
||||
#define FREEPOS 0x08000L /* Memory from FREEPOS to caddr is free to
|
||||
* play with.
|
||||
*/
|
||||
#if BIOS
|
||||
#define MSEC_PER_TICK 55 /* Clock does 18.2 ticks per second. */
|
||||
#define TICKS_PER_DAY 0x1800B0L /* After 24 hours it wraps. */
|
||||
#endif
|
||||
|
||||
#if UNIX
|
||||
#define MSEC_PER_TICK 1000 /* Clock does 18.2 ticks per second. */
|
||||
#define TICKS_PER_DAY 86400L /* Doesn't wrap, but that doesn't matter. */
|
||||
#endif
|
||||
|
||||
#define BOOTPOS 0x07C00L /* Bootstraps are loaded here. */
|
||||
#define SIGNATURE 0xAA55 /* Proper bootstraps have this signature. */
|
||||
#define SIGNATOFF 510 /* Offset within bootblock. */
|
||||
|
||||
/* BIOS video modes. */
|
||||
#define MONO_MODE 0x07 /* 80x25 monochrome. */
|
||||
#define COLOR_MODE 0x03 /* 80x25 color. */
|
||||
|
||||
|
||||
/* Variables shared with boothead.s: */
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
typedef struct vector { /* 8086 vector */
|
||||
u16_t offset;
|
||||
u16_t segment;
|
||||
} vector;
|
||||
|
||||
EXTERN vector rem_part; /* Boot partition table entry. */
|
||||
|
||||
EXTERN u32_t caddr, daddr; /* Code and data address of the boot program. */
|
||||
EXTERN u32_t runsize; /* Size of this program. */
|
||||
|
||||
EXTERN u16_t device; /* Drive being booted from. */
|
||||
|
||||
typedef struct { /* One chunk of free memory. */
|
||||
u32_t base; /* Start byte. */
|
||||
u32_t size; /* Number of bytes. */
|
||||
} memory;
|
||||
|
||||
EXTERN memory mem[3]; /* List of available memory. */
|
||||
EXTERN int mon_return; /* Monitor stays in memory? */
|
||||
|
||||
typedef struct bios_env
|
||||
{
|
||||
u16_t ax;
|
||||
u16_t bx;
|
||||
u16_t cx;
|
||||
u16_t flags;
|
||||
} bios_env_t;
|
||||
|
||||
#define FL_CARRY 0x0001 /* carry flag */
|
||||
|
||||
/* Functions defined by boothead.s: */
|
||||
|
||||
void exit(int code);
|
||||
/* Exit the monitor. */
|
||||
u32_t mon2abs(void *ptr);
|
||||
/* Local monitor address to absolute address. */
|
||||
u32_t vec2abs(vector *vec);
|
||||
/* Vector to absolute address. */
|
||||
void raw_copy(u32_t dstaddr, u32_t srcaddr, u32_t count);
|
||||
/* Copy bytes from anywhere to anywhere. */
|
||||
u16_t get_word(u32_t addr);
|
||||
/* Get a word from anywhere. */
|
||||
void put_word(u32_t addr, U16_t word);
|
||||
/* Put a word anywhere. */
|
||||
void relocate(void);
|
||||
/* Switch to a copy of this program. */
|
||||
int dev_open(void), dev_close(void);
|
||||
/* Open device and determine params / close device. */
|
||||
int dev_boundary(u32_t sector);
|
||||
/* True if sector is on a track boundary. */
|
||||
int readsectors(u32_t bufaddr, u32_t sector, U8_t count);
|
||||
/* Read 1 or more sectors from "device". */
|
||||
int writesectors(u32_t bufaddr, u32_t sector, U8_t count);
|
||||
/* Write 1 or more sectors to "device". */
|
||||
int getch(void);
|
||||
/* Read a keypress. */
|
||||
void scan_keyboard(void);
|
||||
/* Read keypress directly from kb controller. */
|
||||
void ungetch(int c);
|
||||
/* Undo a keypress. */
|
||||
int escape(void);
|
||||
/* True if escape typed. */
|
||||
void putch(int c);
|
||||
/* Send a character to the screen. */
|
||||
#if BIOS
|
||||
void pause(void);
|
||||
/* Wait for an interrupt. */
|
||||
void serial_init(int line);
|
||||
#endif /* Enable copying console I/O to a serial line. */
|
||||
|
||||
void set_mode(unsigned mode);
|
||||
void clear_screen(void);
|
||||
/* Set video mode / clear the screen. */
|
||||
|
||||
u16_t get_bus(void);
|
||||
/* System bus type, XT, AT, or MCA. */
|
||||
u16_t get_video(void);
|
||||
/* Display type, MDA to VGA. */
|
||||
u32_t get_tick(void);
|
||||
/* Current value of the clock tick counter. */
|
||||
|
||||
void bootstrap(int device, struct part_entry *entry);
|
||||
/* Execute a bootstrap routine for a different O.S. */
|
||||
void minix(u32_t koff, u32_t kcs, u32_t kds,
|
||||
char *bootparams, size_t paramsize, u32_t aout);
|
||||
/* Start Minix. */
|
||||
void int15(bios_env_t *);
|
||||
|
||||
|
||||
/* Shared between boot.c and bootimage.c: */
|
||||
|
||||
/* Sticky attributes. */
|
||||
#define E_SPECIAL 0x01 /* These are known to the program. */
|
||||
#define E_DEV 0x02 /* The value is a device name. */
|
||||
#define E_RESERVED 0x04 /* May not be set by user, e.g. 'boot' */
|
||||
#define E_STICKY 0x07 /* Don't go once set. */
|
||||
|
||||
/* Volatile attributes. */
|
||||
#define E_VAR 0x08 /* Variable */
|
||||
#define E_FUNCTION 0x10 /* Function definition. */
|
||||
|
||||
/* Variables, functions, and commands. */
|
||||
typedef struct environment {
|
||||
struct environment *next;
|
||||
char flags;
|
||||
char *name; /* name = value */
|
||||
char *arg; /* name(arg) {value} */
|
||||
char *value;
|
||||
char *defval; /* Safehouse for default values. */
|
||||
} environment;
|
||||
|
||||
EXTERN environment *env; /* Lists the environment. */
|
||||
|
||||
char *b_value(char *name); /* Get/set the value of a variable. */
|
||||
int b_setvar(int flags, char *name, char *value);
|
||||
|
||||
void parse_code(char *code); /* Parse boot monitor commands. */
|
||||
|
||||
extern int fsok; /* True if the boot device contains an FS. */
|
||||
EXTERN u32_t lowsec; /* Offset to the file system on the boot device. */
|
||||
|
||||
/* Called by boot.c: */
|
||||
|
||||
void bootminix(void); /* Load and start a Minix image. */
|
||||
|
||||
|
||||
/* Called by bootimage.c: */
|
||||
|
||||
void readerr(off_t sec, int err);
|
||||
/* Report a read error. */
|
||||
char *ul2a(u32_t n, unsigned b), *ul2a10(u32_t n);
|
||||
/* Transform u32_t to ASCII at base b or base 10. */
|
||||
long a2l(char *a);
|
||||
/* Cheap atol(). */
|
||||
unsigned a2x(char *a);
|
||||
/* ASCII to hex. */
|
||||
dev_t name2dev(char *name);
|
||||
/* Translate a device name to a device number. */
|
||||
int numprefix(char *s, char **ps);
|
||||
/* True for a numeric prefix. */
|
||||
int numeric(char *s);
|
||||
/* True for a numeric string. */
|
||||
char *unix_err(int err);
|
||||
/* Give a descriptive text for some UNIX errors. */
|
||||
int run_trailer(void);
|
||||
/* Run the trailer function. */
|
||||
|
||||
#if DOS
|
||||
/* The monitor runs under MS-DOS. */
|
||||
extern char PSP[256]; /* Program Segment Prefix. */
|
||||
EXTERN char *vdisk; /* Name of the virtual disk. */
|
||||
EXTERN char *drun; /* Initial command from DOS command line. */
|
||||
#else
|
||||
/* The monitor uses only the BIOS. */
|
||||
#define DOS 0
|
||||
#endif
|
||||
|
||||
void readblock(off_t, char *, int);
|
||||
void delay(char *);
|
||||
|
||||
/*
|
||||
* $PchId: boot.h,v 1.12 2002/02/27 19:42:45 philip Exp $
|
||||
*/
|
||||
231
boot/bootblock.s
Executable file
231
boot/bootblock.s
Executable file
@@ -0,0 +1,231 @@
|
||||
! Bootblock 1.5 - Minix boot block. Author: Kees J. Bot
|
||||
! 21 Dec 1991
|
||||
!
|
||||
! When the PC is powered on, it will try to read the first sector of floppy
|
||||
! disk 0 at address 0x7C00. If this fails due to the absence of flexible
|
||||
! magnetic media, it will read the master boot record from the first sector
|
||||
! of the hard disk. This sector not only contains executable code, but also
|
||||
! the partition table of the hard disk. When executed, it will select the
|
||||
! active partition and load the first sector of that at address 0x7C00.
|
||||
! This file contains the code that is eventually read from either the floppy
|
||||
! disk, or the hard disk partition. It is just smart enough to load /boot
|
||||
! from the boot device into memory at address 0x10000 and execute that. The
|
||||
! disk addresses for /boot are patched into this code by installboot as 24-bit
|
||||
! sector numbers and 8-bit sector counts above enddata upwards. /boot is in
|
||||
! turn smart enough to load the different parts of the Minix kernel into
|
||||
! memory and execute them to finally get Minix started.
|
||||
!
|
||||
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BOOTSEG = 0x1000 ! Secondary boot code segment.
|
||||
BOOTOFF = 0x0030 ! Offset into /boot above header
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
LOWSEC = 8 ! Offset of logical first sector in partition
|
||||
! table
|
||||
|
||||
! Variables addressed using bp register
|
||||
device = 0 ! The boot device
|
||||
lowsec = 2 ! Offset of boot partition within drive
|
||||
secpcyl = 6 ! Sectors per cylinder = heads * sectors
|
||||
|
||||
.text
|
||||
|
||||
! Start boot procedure.
|
||||
|
||||
boot:
|
||||
xor ax, ax ! ax = 0x0000, the vector segment
|
||||
mov ds, ax
|
||||
cli ! Ignore interrupts while setting stack
|
||||
mov ss, ax ! ss = ds = vector segment
|
||||
mov sp, #LOADOFF ! Usual place for a bootstrap stack
|
||||
sti
|
||||
|
||||
push ax
|
||||
push ax ! Push a zero lowsec(bp)
|
||||
|
||||
push dx ! Boot device in dl will be device(bp)
|
||||
mov bp, sp ! Using var(bp) is one byte cheaper then var.
|
||||
|
||||
push es
|
||||
push si ! es:si = partition table entry if hard disk
|
||||
|
||||
mov di, #LOADOFF+sectors ! char *di = sectors;
|
||||
|
||||
testb dl, dl ! Winchester disks if dl >= 0x80
|
||||
jge floppy
|
||||
|
||||
winchester:
|
||||
|
||||
! Get the offset of the first sector of the boot partition from the partition
|
||||
! table. The table is found at es:si, the lowsec parameter at offset LOWSEC.
|
||||
|
||||
eseg
|
||||
les ax, LOWSEC(si) ! es:ax = LOWSEC+2(si):LOWSEC(si)
|
||||
mov lowsec+0(bp), ax ! Low 16 bits of partition's first sector
|
||||
mov lowsec+2(bp), es ! High 16 bits of partition's first sector
|
||||
|
||||
! Get the drive parameters, the number of sectors is bluntly written into the
|
||||
! floppy disk sectors/track array.
|
||||
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13 ! dl still contains drive
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
movb (di), cl ! Number of sectors per track
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
jmp loadboot
|
||||
|
||||
! Floppy:
|
||||
! Execute three read tests to determine the drive type. Test for each floppy
|
||||
! type by reading the last sector on the first track. If it fails, try a type
|
||||
! that has less sectors. Therefore we start with 1.44M (18 sectors) then 1.2M
|
||||
! (15 sectors) ending with 720K/360K (both 9 sectors).
|
||||
|
||||
next: inc di ! Next number of sectors per track
|
||||
|
||||
floppy: xorb ah, ah ! Reset drive
|
||||
int 0x13
|
||||
|
||||
movb cl, (di) ! cl = number of last sector on track
|
||||
|
||||
cmpb cl, #9 ! No need to do the last 720K/360K test
|
||||
je success
|
||||
|
||||
! Try to read the last sector on track 0
|
||||
|
||||
mov es, lowsec(bp) ! es = vector segment (lowsec = 0)
|
||||
mov bx, #BUFFER ! es:bx buffer = 0x0000:0x0600
|
||||
mov ax, #0x0201 ! Read sector, #sectors = 1
|
||||
xorb ch, ch ! Track 0, last sector
|
||||
xorb dh, dh ! Drive dl, head 0
|
||||
int 0x13
|
||||
jc next ! Error, try the next floppy type
|
||||
|
||||
success:movb dh, #2 ! Load number of heads for multiply
|
||||
|
||||
loadboot:
|
||||
! Load /boot from the boot device
|
||||
|
||||
movb al, (di) ! al = (di) = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov secpcyl(bp), ax ! Sectors per cylinder = heads * sectors
|
||||
|
||||
mov ax, #BOOTSEG ! Segment to load /boot into
|
||||
mov es, ax
|
||||
xor bx, bx ! Load first sector at es:bx = BOOTSEG:0x0000
|
||||
mov si, #LOADOFF+addresses ! Start of the boot code addresses
|
||||
load:
|
||||
mov ax, 1(si) ! Get next sector number: low 16 bits
|
||||
movb dl, 3(si) ! Bits 16-23 for your up to 8GB partition
|
||||
xorb dh, dh ! dx:ax = sector within partition
|
||||
add ax, lowsec+0(bp)
|
||||
adc dx, lowsec+2(bp)! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div secpcyl(bp) ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb (di) ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
movb dh, al ! dh = al = head
|
||||
movb dl, device(bp) ! dl = device to read
|
||||
movb al, (di) ! Sectors per track - Sector number (0-origin)
|
||||
subb al, ah ! = Sectors left on this track
|
||||
cmpb al, (si) ! Compare with # sectors to read
|
||||
jbe read ! Can't read past the end of a cylinder?
|
||||
movb al, (si) ! (si) < sectors left on this track
|
||||
read: push ax ! Save al = sectors to read
|
||||
movb ah, #0x02 ! Code for disk read (all registers in use now!)
|
||||
int 0x13 ! Call the BIOS for a read
|
||||
pop cx ! Restore al in cl
|
||||
jmp rdeval
|
||||
bigdisk:
|
||||
movb cl, (si) ! Number of sectors to read
|
||||
push si ! Save si
|
||||
mov si, #LOADOFF+ext_rw ! si = extended read/write parameter packet
|
||||
movb 2(si), cl ! Fill in # blocks to transfer
|
||||
mov 4(si), bx ! Buffer address
|
||||
mov 8(si), ax ! Starting block number = dx:ax
|
||||
mov 10(si), dx
|
||||
movb dl, device(bp) ! dl = device to read
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to the addresses array
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jc error ! Jump on disk read error
|
||||
movb al, cl ! Restore al = sectors read
|
||||
addb bh, al ! bx += 2 * al * 256 (add bytes read)
|
||||
addb bh, al ! es:bx = where next sector must be read
|
||||
add 1(si), ax ! Update address by sectors read
|
||||
adcb 3(si), ah ! Don't forget bits 16-23 (add ah = 0)
|
||||
subb (si), al ! Decrement sector count by sectors read
|
||||
jnz load ! Not all sectors have been read
|
||||
add si, #4 ! Next (address, count) pair
|
||||
cmpb ah, (si) ! Done when no sectors to read
|
||||
jnz load ! Read next chunk of /boot
|
||||
|
||||
done:
|
||||
|
||||
! Call /boot, assuming a long a.out header (48 bytes). The a.out header is
|
||||
! usually short (32 bytes), but to be sure /boot has two entry points:
|
||||
! One at offset 0 for the long, and one at offset 16 for the short header.
|
||||
! Parameters passed in registers are:
|
||||
!
|
||||
! dl = Boot-device.
|
||||
! es:si = Partition table entry if hard disk.
|
||||
!
|
||||
pop si ! Restore es:si = partition table entry
|
||||
pop es ! dl is still loaded
|
||||
jmpf BOOTOFF, BOOTSEG ! jmp to sec. boot (skipping header).
|
||||
|
||||
! Read error: print message, hang forever
|
||||
error:
|
||||
mov si, #LOADOFF+errno+1
|
||||
prnum: movb al, ah ! Error number in ah
|
||||
andb al, #0x0F ! Low 4 bits
|
||||
cmpb al, #10 ! A-F?
|
||||
jb digit ! 0-9!
|
||||
addb al, #7 ! 'A' - ':'
|
||||
digit: addb (si), al ! Modify '0' in string
|
||||
dec si
|
||||
movb cl, #4 ! Next 4 bits
|
||||
shrb ah, cl
|
||||
jnz prnum ! Again if digit > 0
|
||||
|
||||
mov si, #LOADOFF+rderr ! String to print
|
||||
print: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null byte marks end
|
||||
hang: jz hang ! Hang forever waiting for CTRL-ALT-DEL
|
||||
movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10 ! Call BIOS VIDEO_IO
|
||||
jmp print
|
||||
|
||||
.data
|
||||
rderr: .ascii "Read error "
|
||||
errno: .ascii "00 \0"
|
||||
errend:
|
||||
|
||||
! Floppy disk sectors per track for the 1.44M, 1.2M and 360K/720K types:
|
||||
sectors:
|
||||
.data1 18, 15, 9
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 0 ! Blocks to transfer (to be filled in)
|
||||
.data2 0 ! Buffer address offset (tbfi)
|
||||
.data2 BOOTSEG ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
.data4 0 ! Starting block number high 32 bits
|
||||
|
||||
.align 2
|
||||
addresses:
|
||||
! The space below this is for disk addresses for a 38K /boot program (worst
|
||||
! case, i.e. file is completely fragmented). It should be enough.
|
||||
1513
boot/boothead.s
Executable file
1513
boot/boothead.s
Executable file
File diff suppressed because it is too large
Load Diff
723
boot/bootimage.c
Executable file
723
boot/bootimage.c
Executable file
@@ -0,0 +1,723 @@
|
||||
/* bootimage.c - Load an image and start it. Author: Kees J. Bot
|
||||
* 19 Jan 1992
|
||||
*/
|
||||
#define BIOS 1 /* Can only be used under the BIOS. */
|
||||
#define nil 0
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _MINIX 1
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <a.out.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/syslib.h>
|
||||
#include <kernel/const.h>
|
||||
#include <kernel/type.h>
|
||||
#include <ibm/partition.h>
|
||||
#include "rawfs.h"
|
||||
#include "image.h"
|
||||
#include "boot.h"
|
||||
|
||||
static int block_size = 0;
|
||||
|
||||
#define click_shift clck_shft /* 7 char clash with click_size. */
|
||||
|
||||
/* Some kernels have extra features: */
|
||||
#define K_I386 0x0001 /* Make the 386 transition before you call me. */
|
||||
#define K_CLAIM 0x0002 /* I will acquire my own bss pages, thank you. */
|
||||
#define K_CHMEM 0x0004 /* This kernel listens to chmem for its stack size. */
|
||||
#define K_HIGH 0x0008 /* Load mm, fs, etc. in extended memory. */
|
||||
#define K_HDR 0x0010 /* No need to patch sizes, kernel uses the headers. */
|
||||
#define K_RET 0x0020 /* Returns to the monitor on reboot. */
|
||||
#define K_INT86 0x0040 /* Requires generic INT support. */
|
||||
#define K_MEML 0x0080 /* Pass a list of free memory. */
|
||||
#define K_BRET 0x0100 /* New monitor code on shutdown in boot parameters. */
|
||||
#define K_ALL 0x01FF /* All feature bits this monitor supports. */
|
||||
|
||||
|
||||
/* Data about the different processes. */
|
||||
|
||||
#define PROCESS_MAX 16 /* Must match the space in kernel/mpx.x */
|
||||
#define KERNEL 0 /* The first process is the kernel. */
|
||||
#define FS 2 /* The third must be fs. */
|
||||
|
||||
struct process { /* Per-process memory adresses. */
|
||||
u32_t entry; /* Entry point. */
|
||||
u32_t cs; /* Code segment. */
|
||||
u32_t ds; /* Data segment. */
|
||||
u32_t data; /* To access the data segment. */
|
||||
u32_t end; /* End of this process, size = (end - cs). */
|
||||
} process[PROCESS_MAX];
|
||||
int n_procs; /* Number of processes. */
|
||||
|
||||
/* Magic numbers in process' data space. */
|
||||
#define MAGIC_OFF 0 /* Offset of magic # in data seg. */
|
||||
#define CLICK_OFF 2 /* Offset in kernel text to click_shift. */
|
||||
#define FLAGS_OFF 4 /* Offset in kernel text to flags. */
|
||||
#define KERNEL_D_MAGIC 0x526F /* Kernel magic number. */
|
||||
|
||||
/* Offsets of sizes to be patched into kernel and fs. */
|
||||
#define P_SIZ_OFF 0 /* Process' sizes into kernel data. */
|
||||
#define P_INIT_OFF 4 /* Init cs & sizes into fs data. */
|
||||
|
||||
|
||||
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
|
||||
|
||||
void pretty_image(char *image)
|
||||
/* Pretty print the name of the image to load. Translate '/' and '_' to
|
||||
* space, first letter goes uppercase. An 'r' before a digit prints as
|
||||
* 'revision'. E.g. 'minix/1.6.16r10' -> 'Minix 1.6.16 revision 10'.
|
||||
* The idea is that the part before the 'r' is the official Minix release
|
||||
* and after the 'r' you can put version numbers for your own changes.
|
||||
*/
|
||||
{
|
||||
int up= 0, c;
|
||||
|
||||
while ((c= *image++) != 0) {
|
||||
if (c == '/' || c == '_') c= ' ';
|
||||
|
||||
if (c == 'r' && between('0', *image, '9')) {
|
||||
printf(" revision ");
|
||||
continue;
|
||||
}
|
||||
if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
|
||||
|
||||
if (between('A', c, 'Z')) up= 1;
|
||||
|
||||
putch(c);
|
||||
}
|
||||
}
|
||||
|
||||
void raw_clear(u32_t addr, u32_t count)
|
||||
/* Clear "count" bytes at absolute address "addr". */
|
||||
{
|
||||
static char zeros[128];
|
||||
u32_t dst;
|
||||
u32_t zct;
|
||||
|
||||
zct= sizeof(zeros);
|
||||
if (zct > count) zct= count;
|
||||
raw_copy(addr, mon2abs(&zeros), zct);
|
||||
count-= zct;
|
||||
|
||||
while (count > 0) {
|
||||
dst= addr + zct;
|
||||
if (zct > count) zct= count;
|
||||
raw_copy(dst, addr, zct);
|
||||
count-= zct;
|
||||
zct*= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Align a to a multiple of n (a power of 2): */
|
||||
#define align(a, n) (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
|
||||
unsigned click_shift;
|
||||
unsigned click_size; /* click_size = Smallest kernel memory object. */
|
||||
unsigned k_flags; /* Not all kernels are created equal. */
|
||||
u32_t reboot_code; /* Obsolete reboot code return pointer. */
|
||||
|
||||
int params2params(char *params, size_t psize)
|
||||
/* Repackage the environment settings for the kernel. */
|
||||
{
|
||||
size_t i, n;
|
||||
environment *e;
|
||||
char *name, *value;
|
||||
dev_t dev;
|
||||
|
||||
i= 0;
|
||||
for (e= env; e != nil; e= e->next) {
|
||||
name= e->name;
|
||||
value= e->value;
|
||||
|
||||
if (!(e->flags & E_VAR)) continue;
|
||||
|
||||
if (e->flags & E_DEV) {
|
||||
if ((dev= name2dev(value)) == -1) return 0;
|
||||
value= ul2a10((u16_t) dev);
|
||||
}
|
||||
|
||||
n= i + strlen(name) + 1 + strlen(value) + 1;
|
||||
if (n < psize) {
|
||||
strcpy(params + i, name);
|
||||
strcat(params + i, "=");
|
||||
strcat(params + i, value);
|
||||
}
|
||||
i= n;
|
||||
}
|
||||
|
||||
if (!(k_flags & K_MEML)) {
|
||||
/* Require old memory size variables. */
|
||||
|
||||
value= ul2a10((mem[0].base + mem[0].size) / 1024);
|
||||
n= i + 7 + 1 + strlen(value) + 1;
|
||||
if (n < psize) {
|
||||
strcpy(params + i, "memsize=");
|
||||
strcat(params + i, value);
|
||||
}
|
||||
i= n;
|
||||
value= ul2a10(mem[1].size / 1024);
|
||||
n= i + 7 + 1 + strlen(value) + 1;
|
||||
if (n < psize) {
|
||||
strcpy(params + i, "emssize=");
|
||||
strcat(params + i, value);
|
||||
}
|
||||
i= n;
|
||||
}
|
||||
|
||||
if (i >= psize) {
|
||||
printf("Too many boot parameters\n");
|
||||
return 0;
|
||||
}
|
||||
params[i]= 0; /* End marked with empty string. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void patch_sizes(void)
|
||||
/* Patch sizes of each process into kernel data space, kernel ds into kernel
|
||||
* text space, and sizes of init into data space of fs. All the patched
|
||||
* numbers are based on the kernel click size, not hardware segments.
|
||||
*/
|
||||
{
|
||||
u16_t text_size, data_size;
|
||||
int i;
|
||||
struct process *procp, *initp;
|
||||
u32_t doff;
|
||||
|
||||
if (k_flags & K_HDR) return; /* Uses the headers. */
|
||||
|
||||
/* Patch text and data sizes of the processes into kernel data space.
|
||||
*/
|
||||
doff= process[KERNEL].data + P_SIZ_OFF;
|
||||
|
||||
for (i= 0; i < n_procs; i++) {
|
||||
procp= &process[i];
|
||||
text_size= (procp->ds - procp->cs) >> click_shift;
|
||||
data_size= (procp->end - procp->ds) >> click_shift;
|
||||
|
||||
/* Two words per process, the text and data size: */
|
||||
put_word(doff, text_size); doff+= 2;
|
||||
put_word(doff, data_size); doff+= 2;
|
||||
|
||||
initp= procp; /* The last process must be init. */
|
||||
}
|
||||
|
||||
if (k_flags & (K_HIGH|K_MEML)) return; /* Doesn't need FS patching. */
|
||||
|
||||
/* Patch cs and sizes of init into fs data. */
|
||||
put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
|
||||
put_word(process[FS].data + P_INIT_OFF+2, text_size);
|
||||
put_word(process[FS].data + P_INIT_OFF+4, data_size);
|
||||
}
|
||||
|
||||
int selected(char *name)
|
||||
/* True iff name has no label or the proper label. */
|
||||
{
|
||||
char *colon, *label;
|
||||
int cmp;
|
||||
|
||||
if ((colon= strchr(name, ':')) == nil) return 1;
|
||||
if ((label= b_value("label")) == nil) return 1;
|
||||
|
||||
*colon= 0;
|
||||
cmp= strcmp(label, name);
|
||||
*colon= ':';
|
||||
return cmp == 0;
|
||||
}
|
||||
|
||||
u32_t proc_size(struct image_header *hdr)
|
||||
/* Return the size of a process in sectors as found in an image. */
|
||||
{
|
||||
u32_t len= hdr->process.a_text;
|
||||
|
||||
if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
|
||||
if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
|
||||
len= align(len + hdr->process.a_data, SECTOR_SIZE);
|
||||
|
||||
return len >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
off_t image_off, image_size;
|
||||
u32_t (*vir2sec)(u32_t vsec); /* Where is a sector on disk? */
|
||||
|
||||
u32_t file_vir2sec(u32_t vsec)
|
||||
/* Translate a virtual sector number to an absolute disk sector. */
|
||||
{
|
||||
off_t blk;
|
||||
|
||||
if(!block_size) { errno = 0; return -1; }
|
||||
|
||||
if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
|
||||
errno= EIO;
|
||||
return -1;
|
||||
}
|
||||
return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
|
||||
}
|
||||
|
||||
u32_t flat_vir2sec(u32_t vsec)
|
||||
/* Simply add an absolute sector offset to vsec. */
|
||||
{
|
||||
return lowsec + image_off + vsec;
|
||||
}
|
||||
|
||||
char *get_sector(u32_t vsec)
|
||||
/* Read a sector "vsec" from the image into memory and return its address.
|
||||
* Return nil on error. (This routine tries to read an entire track, so
|
||||
* the next request is usually satisfied from the track buffer.)
|
||||
*/
|
||||
{
|
||||
u32_t sec;
|
||||
int r;
|
||||
#define SECBUFS 16
|
||||
static char buf[SECBUFS * SECTOR_SIZE];
|
||||
static size_t count; /* Number of sectors in the buffer. */
|
||||
static u32_t bufsec; /* First Sector now in the buffer. */
|
||||
|
||||
if (vsec == 0) count= 0; /* First sector; initialize. */
|
||||
|
||||
if ((sec= (*vir2sec)(vsec)) == -1) return nil;
|
||||
|
||||
if (sec == 0) {
|
||||
/* A hole. */
|
||||
count= 0;
|
||||
memset(buf, 0, SECTOR_SIZE);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Can we return a sector from the buffer? */
|
||||
if ((sec - bufsec) < count) {
|
||||
return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
|
||||
}
|
||||
|
||||
/* Not in the buffer. */
|
||||
count= 0;
|
||||
bufsec= sec;
|
||||
|
||||
/* Read a whole track if possible. */
|
||||
while (++count < SECBUFS && !dev_boundary(bufsec + count)) {
|
||||
vsec++;
|
||||
if ((sec= (*vir2sec)(vsec)) == -1) break;
|
||||
|
||||
/* Consecutive? */
|
||||
if (sec != bufsec + count) break;
|
||||
}
|
||||
|
||||
/* Actually read the sectors. */
|
||||
if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
|
||||
readerr(bufsec, r);
|
||||
count= 0;
|
||||
errno= 0;
|
||||
return nil;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int get_clickshift(u32_t ksec, struct image_header *hdr)
|
||||
/* Get the click shift and special flags from kernel text. */
|
||||
{
|
||||
char *textp;
|
||||
|
||||
if ((textp= get_sector(ksec)) == nil) return 0;
|
||||
|
||||
if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
|
||||
click_shift= * (u16_t *) (textp + CLICK_OFF);
|
||||
k_flags= * (u16_t *) (textp + FLAGS_OFF);
|
||||
|
||||
if ((k_flags & ~K_ALL) != 0) {
|
||||
printf("%s requires features this monitor doesn't offer\n",
|
||||
hdr->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (click_shift < HCLICK_SHIFT || click_shift > 16) {
|
||||
printf("%s click size is bad\n", hdr->name);
|
||||
errno= 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
click_size= 1 << click_shift;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
|
||||
/* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
|
||||
{
|
||||
char *buf;
|
||||
size_t cnt, n;
|
||||
|
||||
cnt= 0;
|
||||
while (*size > 0) {
|
||||
if (cnt == 0) {
|
||||
if ((buf= get_sector((*vsec)++)) == nil) return 0;
|
||||
cnt= SECTOR_SIZE;
|
||||
}
|
||||
if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
|
||||
n= click_size;
|
||||
if (n > cnt) n= cnt;
|
||||
raw_copy(*addr, mon2abs(buf), n);
|
||||
*addr+= n;
|
||||
*size-= n;
|
||||
buf+= n;
|
||||
cnt-= n;
|
||||
}
|
||||
|
||||
/* Zero extend to a click. */
|
||||
n= align(*addr, click_size) - *addr;
|
||||
raw_clear(*addr, n);
|
||||
*addr+= n;
|
||||
*size-= n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void exec_image(char *image)
|
||||
/* Get a Minix image into core, patch it up and execute. */
|
||||
{
|
||||
char *delayvalue;
|
||||
int i;
|
||||
struct image_header hdr;
|
||||
char *buf;
|
||||
u32_t vsec, addr, limit, aout, n;
|
||||
struct process *procp; /* Process under construction. */
|
||||
long a_text, a_data, a_bss, a_stack;
|
||||
int banner= 0;
|
||||
long processor= a2l(b_value("processor"));
|
||||
u16_t mode;
|
||||
char *console;
|
||||
char params[SECTOR_SIZE];
|
||||
extern char *sbrk(int);
|
||||
|
||||
/* The stack is pretty deep here, so check if heap and stack collide. */
|
||||
(void) sbrk(0);
|
||||
|
||||
printf("\nLoading ");
|
||||
pretty_image(image);
|
||||
printf(".\n\n");
|
||||
|
||||
vsec= 0; /* Load this sector from image next. */
|
||||
addr= mem[0].base; /* Into this memory block. */
|
||||
limit= mem[0].base + mem[0].size;
|
||||
if (limit > caddr) limit= caddr;
|
||||
|
||||
/* Allocate and clear the area where the headers will be placed. */
|
||||
aout = (limit -= PROCESS_MAX * A_MINHDR);
|
||||
|
||||
/* Clear the area where the headers will be placed. */
|
||||
raw_clear(aout, PROCESS_MAX * A_MINHDR);
|
||||
|
||||
/* Read the many different processes: */
|
||||
for (i= 0; vsec < image_size; i++) {
|
||||
if (i == PROCESS_MAX) {
|
||||
printf("There are more then %d programs in %s\n",
|
||||
PROCESS_MAX, image);
|
||||
errno= 0;
|
||||
return;
|
||||
}
|
||||
procp= &process[i];
|
||||
|
||||
/* Read header. */
|
||||
for (;;) {
|
||||
if ((buf= get_sector(vsec++)) == nil) return;
|
||||
|
||||
memcpy(&hdr, buf, sizeof(hdr));
|
||||
|
||||
if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
|
||||
|
||||
/* Check the optional label on the process. */
|
||||
if (selected(hdr.name)) break;
|
||||
|
||||
/* Bad label, skip this process. */
|
||||
vsec+= proc_size(&hdr);
|
||||
}
|
||||
|
||||
/* Sanity check: an 8086 can't run a 386 kernel. */
|
||||
if (hdr.process.a_cpu == A_I80386 && processor < 386) {
|
||||
printf("You can't run a 386 kernel on this 80%ld\n",
|
||||
processor);
|
||||
errno= 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the click shift from the kernel text segment. */
|
||||
if (i == KERNEL) {
|
||||
if (!get_clickshift(vsec, &hdr)) return;
|
||||
addr= align(addr, click_size);
|
||||
}
|
||||
|
||||
/* Save a copy of the header for the kernel, with a_syms
|
||||
* misused as the address where the process is loaded at.
|
||||
*/
|
||||
hdr.process.a_syms= addr;
|
||||
raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
|
||||
|
||||
if (!banner) {
|
||||
printf(" cs ds text data bss");
|
||||
if (k_flags & K_CHMEM) printf(" stack");
|
||||
putch('\n');
|
||||
banner= 1;
|
||||
}
|
||||
|
||||
/* Segment sizes. */
|
||||
a_text= hdr.process.a_text;
|
||||
a_data= hdr.process.a_data;
|
||||
a_bss= hdr.process.a_bss;
|
||||
if (k_flags & K_CHMEM) {
|
||||
a_stack= hdr.process.a_total - a_data - a_bss;
|
||||
if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
|
||||
} else {
|
||||
a_stack= 0;
|
||||
}
|
||||
|
||||
/* Collect info about the process to be. */
|
||||
procp->cs= addr;
|
||||
|
||||
/* Process may be page aligned so that the text segment contains
|
||||
* the header, or have an unmapped zero page against vaxisms.
|
||||
*/
|
||||
procp->entry= hdr.process.a_entry;
|
||||
if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
|
||||
if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
|
||||
|
||||
/* Separate I&D: two segments. Common I&D: only one. */
|
||||
if (hdr.process.a_flags & A_SEP) {
|
||||
/* Read the text segment. */
|
||||
if (!get_segment(&vsec, &a_text, &addr, limit)) return;
|
||||
|
||||
/* The data segment follows. */
|
||||
procp->ds= addr;
|
||||
if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
|
||||
procp->data= addr;
|
||||
} else {
|
||||
/* Add text to data to form one segment. */
|
||||
procp->data= addr + a_text;
|
||||
procp->ds= procp->cs;
|
||||
a_data+= a_text;
|
||||
}
|
||||
|
||||
/* Read the data segment. */
|
||||
if (!get_segment(&vsec, &a_data, &addr, limit)) return;
|
||||
|
||||
/* Make space for bss and stack unless... */
|
||||
if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
|
||||
|
||||
printf("%07lx %07lx %8ld %8ld %8ld",
|
||||
procp->cs, procp->ds,
|
||||
hdr.process.a_text, hdr.process.a_data,
|
||||
hdr.process.a_bss
|
||||
);
|
||||
if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
|
||||
|
||||
printf(" %s\n", hdr.name);
|
||||
|
||||
/* Note that a_data may be negative now, but we can look at it
|
||||
* as -a_data bss bytes.
|
||||
*/
|
||||
|
||||
/* Compute the number of bss clicks left. */
|
||||
a_bss+= a_data;
|
||||
n= align(a_bss, click_size);
|
||||
a_bss-= n;
|
||||
|
||||
/* Zero out bss. */
|
||||
if (addr + n > limit) { errno= ENOMEM; return; }
|
||||
raw_clear(addr, n);
|
||||
addr+= n;
|
||||
|
||||
/* And the number of stack clicks. */
|
||||
a_stack+= a_bss;
|
||||
n= align(a_stack, click_size);
|
||||
a_stack-= n;
|
||||
|
||||
/* Add space for the stack. */
|
||||
addr+= n;
|
||||
|
||||
/* Process endpoint. */
|
||||
procp->end= addr;
|
||||
|
||||
if (i == 0 && (k_flags & K_HIGH)) {
|
||||
/* Load the rest in extended memory. */
|
||||
addr= mem[1].base;
|
||||
limit= mem[1].base + mem[1].size;
|
||||
}
|
||||
}
|
||||
|
||||
if ((n_procs= i) == 0) {
|
||||
printf("There are no programs in %s\n", image);
|
||||
errno= 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the kernel magic number. */
|
||||
if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
|
||||
printf("Kernel magic number is incorrect\n");
|
||||
errno= 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Patch sizes, etc. into kernel data. */
|
||||
patch_sizes();
|
||||
|
||||
#if !DOS
|
||||
if (!(k_flags & K_MEML)) {
|
||||
/* Copy the a.out headers to the old place. */
|
||||
raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do delay if wanted. */
|
||||
if((delayvalue = b_value("bootdelay")) != nil > 0) {
|
||||
delay(delayvalue);
|
||||
}
|
||||
|
||||
/* Run the trailer function just before starting Minix. */
|
||||
if (!run_trailer()) { errno= 0; return; }
|
||||
|
||||
/* Translate the boot parameters to what Minix likes best. */
|
||||
if (!params2params(params, sizeof(params))) { errno= 0; return; }
|
||||
|
||||
/* Set the video to the required mode. */
|
||||
if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
|
||||
mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
|
||||
MONO_MODE;
|
||||
}
|
||||
set_mode(mode);
|
||||
|
||||
/* Close the disk. */
|
||||
(void) dev_close();
|
||||
|
||||
/* Minix. */
|
||||
minix(process[KERNEL].entry, process[KERNEL].cs,
|
||||
process[KERNEL].ds, params, sizeof(params), aout);
|
||||
|
||||
if (!(k_flags & K_BRET)) {
|
||||
extern u32_t reboot_code;
|
||||
raw_copy(mon2abs(params), reboot_code, sizeof(params));
|
||||
}
|
||||
parse_code(params);
|
||||
|
||||
/* Return from Minix. Things may have changed, so assume nothing. */
|
||||
fsok= -1;
|
||||
errno= 0;
|
||||
|
||||
/* Read leftover character, if any. */
|
||||
scan_keyboard();
|
||||
}
|
||||
|
||||
ino_t latest_version(char *version, struct stat *stp)
|
||||
/* Recursively read the current directory, selecting the newest image on
|
||||
* the way up. (One can't use r_stat while reading a directory.)
|
||||
*/
|
||||
{
|
||||
char name[NAME_MAX + 1];
|
||||
ino_t ino, newest;
|
||||
time_t mtime;
|
||||
|
||||
if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
|
||||
|
||||
newest= latest_version(version, stp);
|
||||
mtime= stp->st_mtime;
|
||||
r_stat(ino, stp);
|
||||
|
||||
if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
|
||||
newest= ino;
|
||||
strcpy(version, name);
|
||||
} else {
|
||||
stp->st_mtime= mtime;
|
||||
}
|
||||
return newest;
|
||||
}
|
||||
|
||||
char *select_image(char *image)
|
||||
/* Look image up on the filesystem, if it is a file then we're done, but
|
||||
* if its a directory then we want the newest file in that directory. If
|
||||
* it doesn't exist at all, then see if it is 'number:number' and get the
|
||||
* image from that absolute offset off the disk.
|
||||
*/
|
||||
{
|
||||
ino_t image_ino;
|
||||
struct stat st;
|
||||
|
||||
image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
|
||||
* sizeof(char)), image);
|
||||
|
||||
fsok= r_super(&block_size) != 0;
|
||||
if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
|
||||
char *size;
|
||||
|
||||
if (numprefix(image, &size) && *size++ == ':'
|
||||
&& numeric(size)) {
|
||||
vir2sec= flat_vir2sec;
|
||||
image_off= a2l(image);
|
||||
image_size= a2l(size);
|
||||
strcpy(image, "Minix");
|
||||
return image;
|
||||
}
|
||||
if (!fsok)
|
||||
printf("No image selected\n");
|
||||
else
|
||||
printf("Can't load %s: %s\n", image, unix_err(errno));
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
r_stat(image_ino, &st);
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
char *version= image + strlen(image);
|
||||
char dots[NAME_MAX + 1];
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
printf("%s: %s\n", image, unix_err(ENOTDIR));
|
||||
goto bail_out;
|
||||
}
|
||||
(void) r_readdir(dots);
|
||||
(void) r_readdir(dots); /* "." & ".." */
|
||||
*version++= '/';
|
||||
*version= 0;
|
||||
if ((image_ino= latest_version(version, &st)) == 0) {
|
||||
printf("There are no images in %s\n", image);
|
||||
goto bail_out;
|
||||
}
|
||||
r_stat(image_ino, &st);
|
||||
}
|
||||
vir2sec= file_vir2sec;
|
||||
image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
|
||||
return image;
|
||||
bail_out:
|
||||
free(image);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void bootminix(void)
|
||||
/* Load Minix and run it. (Given the size of this program it is surprising
|
||||
* that it ever gets to that.)
|
||||
*/
|
||||
{
|
||||
char *image;
|
||||
|
||||
if ((image= select_image(b_value("image"))) == nil) return;
|
||||
|
||||
exec_image(image);
|
||||
|
||||
switch (errno) {
|
||||
case ENOEXEC:
|
||||
printf("%s contains a bad program header\n", image);
|
||||
break;
|
||||
case ENOMEM:
|
||||
printf("Not enough memory to load %s\n", image);
|
||||
break;
|
||||
case EIO:
|
||||
printf("Unsuspected EOF on %s\n", image);
|
||||
case 0:
|
||||
/* No error or error already reported. */;
|
||||
}
|
||||
free(image);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
|
||||
*/
|
||||
1369
boot/doshead.s
Executable file
1369
boot/doshead.s
Executable file
File diff suppressed because it is too large
Load Diff
13
boot/image.h
Executable file
13
boot/image.h
Executable file
@@ -0,0 +1,13 @@
|
||||
/* image.h - Info between installboot and boot. Author: Kees J. Bot
|
||||
*/
|
||||
|
||||
#define IM_NAME_MAX 63
|
||||
|
||||
struct image_header {
|
||||
char name[IM_NAME_MAX + 1]; /* Null terminated. */
|
||||
struct exec process;
|
||||
};
|
||||
|
||||
/*
|
||||
* $PchId: image.h,v 1.4 1995/11/27 22:23:12 philip Exp $
|
||||
*/
|
||||
833
boot/installboot.c
Executable file
833
boot/installboot.c
Executable file
@@ -0,0 +1,833 @@
|
||||
/* installboot 3.0 - Make a device bootable Author: Kees J. Bot
|
||||
* 21 Dec 1991
|
||||
*
|
||||
* Either make a device bootable or make an image from kernel, mm, fs, etc.
|
||||
*/
|
||||
#define nil 0
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _MINIX 1
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <a.out.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/partition.h>
|
||||
#include <minix/u64.h>
|
||||
#include "rawfs.h"
|
||||
#include "image.h"
|
||||
|
||||
#define BOOTBLOCK 0 /* Of course */
|
||||
#define SECTOR_SIZE 512 /* Disk sector size. */
|
||||
#define RATIO(b) ((b)/SECTOR_SIZE)
|
||||
#define SIGNATURE 0xAA55 /* Boot block signature. */
|
||||
#define BOOT_MAX 64 /* Absolute maximum size of secondary boot */
|
||||
#define SIGPOS 510 /* Where to put signature word. */
|
||||
#define PARTPOS 446 /* Offset to the partition table in a master
|
||||
* boot block.
|
||||
*/
|
||||
|
||||
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
|
||||
#define control(c) between('\0', (c), '\37')
|
||||
|
||||
#define BOOT_BLOCK_SIZE 1024
|
||||
|
||||
void report(char *label)
|
||||
/* installboot: label: No such file or directory */
|
||||
{
|
||||
fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
|
||||
}
|
||||
|
||||
void fatal(char *label)
|
||||
{
|
||||
report(label);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *basename(char *name)
|
||||
/* Return the last component of name, stripping trailing slashes from name.
|
||||
* Precondition: name != "/". If name is prefixed by a label, then the
|
||||
* label is copied to the basename too.
|
||||
*/
|
||||
{
|
||||
static char base[IM_NAME_MAX];
|
||||
char *p, *bp= base;
|
||||
|
||||
if ((p= strchr(name, ':')) != nil) {
|
||||
while (name <= p && bp < base + IM_NAME_MAX - 1)
|
||||
*bp++ = *name++;
|
||||
}
|
||||
for (;;) {
|
||||
if ((p= strrchr(name, '/')) == nil) { p= name; break; }
|
||||
if (*++p != 0) break;
|
||||
*--p= 0;
|
||||
}
|
||||
while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
|
||||
*bp= 0;
|
||||
return base;
|
||||
}
|
||||
|
||||
void bread(FILE *f, char *name, void *buf, size_t len)
|
||||
/* Read len bytes. Don't dare return without them. */
|
||||
{
|
||||
if (len > 0 && fread(buf, len, 1, f) != 1) {
|
||||
if (ferror(f)) fatal(name);
|
||||
fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void bwrite(FILE *f, char *name, void *buf, size_t len)
|
||||
{
|
||||
if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
|
||||
}
|
||||
|
||||
long total_text= 0, total_data= 0, total_bss= 0;
|
||||
int making_image= 0;
|
||||
|
||||
void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
|
||||
/* Read the a.out header of a program and check it. If procf happens to be
|
||||
* nil then the header is already in *image_hdr and need only be checked.
|
||||
*/
|
||||
{
|
||||
int n, big= 0;
|
||||
static int banner= 0;
|
||||
struct exec *phdr= &ihdr->process;
|
||||
|
||||
if (procf == nil) {
|
||||
/* Header already present. */
|
||||
n= phdr->a_hdrlen;
|
||||
} else {
|
||||
memset(ihdr, 0, sizeof(*ihdr));
|
||||
|
||||
/* Put the basename of proc in the header. */
|
||||
strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
|
||||
|
||||
/* Read the header. */
|
||||
n= fread(phdr, sizeof(char), A_MINHDR, procf);
|
||||
if (ferror(procf)) fatal(proc);
|
||||
}
|
||||
|
||||
if (n < A_MINHDR || BADMAG(*phdr)) {
|
||||
fprintf(stderr, "installboot: %s is not an executable\n", proc);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the rest of the exec header. */
|
||||
if (procf != nil) {
|
||||
bread(procf, proc, ((char *) phdr) + A_MINHDR,
|
||||
phdr->a_hdrlen - A_MINHDR);
|
||||
}
|
||||
|
||||
if (talk && !banner) {
|
||||
printf(" text data bss size\n");
|
||||
banner= 1;
|
||||
}
|
||||
|
||||
if (talk) {
|
||||
printf(" %8ld %8ld %8ld %9ld %s\n",
|
||||
phdr->a_text, phdr->a_data, phdr->a_bss,
|
||||
phdr->a_text + phdr->a_data + phdr->a_bss, proc);
|
||||
}
|
||||
total_text+= phdr->a_text;
|
||||
total_data+= phdr->a_data;
|
||||
total_bss+= phdr->a_bss;
|
||||
|
||||
if (phdr->a_cpu == A_I8086) {
|
||||
long data= phdr->a_data + phdr->a_bss;
|
||||
|
||||
if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
|
||||
|
||||
if (phdr->a_text >= 65536) big|= 1;
|
||||
if (data >= 65536) big|= 2;
|
||||
}
|
||||
if (big) {
|
||||
fprintf(stderr,
|
||||
"%s will crash, %s%s%s segment%s larger then 64K\n",
|
||||
proc,
|
||||
big & 1 ? "text" : "",
|
||||
big == 3 ? " and " : "",
|
||||
big & 2 ? "data" : "",
|
||||
big == 3 ? "s are" : " is");
|
||||
}
|
||||
}
|
||||
|
||||
void padimage(char *image, FILE *imagef, int n)
|
||||
/* Add n zeros to image to pad it to a sector boundary. */
|
||||
{
|
||||
while (n > 0) {
|
||||
if (putc(0, imagef) == EOF) fatal(image);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
#define align(n) (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
|
||||
|
||||
void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
|
||||
/* Copy n bytes from proc to image padded to fill a sector. */
|
||||
{
|
||||
int pad, c;
|
||||
|
||||
/* Compute number of padding bytes. */
|
||||
pad= align(n) - n;
|
||||
|
||||
while (n > 0) {
|
||||
if ((c= getc(procf)) == EOF) {
|
||||
if (ferror(procf)) fatal(proc);
|
||||
fprintf(stderr, "installboot: premature EOF on %s\n",
|
||||
proc);
|
||||
exit(1);
|
||||
}
|
||||
if (putc(c, imagef) == EOF) fatal(image);
|
||||
n--;
|
||||
}
|
||||
padimage(image, imagef, pad);
|
||||
}
|
||||
|
||||
void make_image(char *image, char **procv)
|
||||
/* Collect a set of files in an image, each "segment" is nicely padded out
|
||||
* to SECTOR_SIZE, so it may be read from disk into memory without trickery.
|
||||
*/
|
||||
{
|
||||
FILE *imagef, *procf;
|
||||
char *proc, *file;
|
||||
int procn;
|
||||
struct image_header ihdr;
|
||||
struct exec phdr;
|
||||
struct stat st;
|
||||
|
||||
making_image= 1;
|
||||
|
||||
if ((imagef= fopen(image, "w")) == nil) fatal(image);
|
||||
|
||||
for (procn= 0; (proc= *procv++) != nil; procn++) {
|
||||
/* Remove the label from the file name. */
|
||||
if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
|
||||
|
||||
/* Real files please, may need to seek. */
|
||||
if (stat(file, &st) < 0
|
||||
|| (errno= EISDIR, !S_ISREG(st.st_mode))
|
||||
|| (procf= fopen(file, "r")) == nil
|
||||
) fatal(proc);
|
||||
|
||||
/* Read a.out header. */
|
||||
read_header(1, proc, procf, &ihdr);
|
||||
|
||||
/* Scratch. */
|
||||
phdr= ihdr.process;
|
||||
|
||||
/* The symbol table is always stripped off. */
|
||||
ihdr.process.a_syms= 0;
|
||||
ihdr.process.a_flags &= ~A_NSYM;
|
||||
|
||||
/* Write header padded to fill a sector */
|
||||
bwrite(imagef, image, &ihdr, sizeof(ihdr));
|
||||
|
||||
padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
|
||||
|
||||
/* A page aligned executable needs the header in text. */
|
||||
if (phdr.a_flags & A_PAL) {
|
||||
rewind(procf);
|
||||
phdr.a_text+= phdr.a_hdrlen;
|
||||
}
|
||||
|
||||
/* Copy text and data of proc to image. */
|
||||
if (phdr.a_flags & A_SEP) {
|
||||
/* Separate I&D: pad text & data separately. */
|
||||
|
||||
copyexec(proc, procf, image, imagef, phdr.a_text);
|
||||
copyexec(proc, procf, image, imagef, phdr.a_data);
|
||||
} else {
|
||||
/* Common I&D: keep text and data together. */
|
||||
|
||||
copyexec(proc, procf, image, imagef,
|
||||
phdr.a_text + phdr.a_data);
|
||||
}
|
||||
|
||||
/* Done with proc. */
|
||||
(void) fclose(procf);
|
||||
}
|
||||
/* Done with image. */
|
||||
|
||||
if (fclose(imagef) == EOF) fatal(image);
|
||||
|
||||
printf(" ------ ------ ------ -------\n");
|
||||
printf(" %8ld %8ld %8ld %9ld total\n",
|
||||
total_text, total_data, total_bss,
|
||||
total_text + total_data + total_bss);
|
||||
}
|
||||
|
||||
void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
|
||||
long count, off_t *alen)
|
||||
/* Copy a segment of an executable. It is padded to a sector in image. */
|
||||
{
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
while (count > 0) {
|
||||
bread(imagef, image, buf, sizeof(buf));
|
||||
*alen-= sizeof(buf);
|
||||
|
||||
bwrite(procf, proc, buf,
|
||||
count < sizeof(buf) ? (size_t) count : sizeof(buf));
|
||||
count-= sizeof(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void extract_image(char *image)
|
||||
/* Extract the executables from an image. */
|
||||
{
|
||||
FILE *imagef, *procf;
|
||||
off_t len;
|
||||
struct stat st;
|
||||
struct image_header ihdr;
|
||||
struct exec phdr;
|
||||
char buf[SECTOR_SIZE];
|
||||
|
||||
if (stat(image, &st) < 0) fatal(image);
|
||||
|
||||
/* Size of the image. */
|
||||
len= S_ISREG(st.st_mode) ? st.st_size : -1;
|
||||
|
||||
if ((imagef= fopen(image, "r")) == nil) fatal(image);
|
||||
|
||||
while (len != 0) {
|
||||
/* Extract a program, first sector is an extended header. */
|
||||
bread(imagef, image, buf, sizeof(buf));
|
||||
len-= sizeof(buf);
|
||||
|
||||
memcpy(&ihdr, buf, sizeof(ihdr));
|
||||
phdr= ihdr.process;
|
||||
|
||||
/* Check header. */
|
||||
read_header(1, ihdr.name, nil, &ihdr);
|
||||
|
||||
if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
|
||||
|
||||
if (phdr.a_flags & A_PAL) {
|
||||
/* A page aligned process contains a header in text. */
|
||||
phdr.a_text+= phdr.a_hdrlen;
|
||||
} else {
|
||||
bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
|
||||
}
|
||||
|
||||
/* Extract text and data segments. */
|
||||
if (phdr.a_flags & A_SEP) {
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_text, &len);
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_data, &len);
|
||||
} else {
|
||||
extractexec(imagef, image, procf, ihdr.name,
|
||||
phdr.a_text + phdr.a_data, &len);
|
||||
}
|
||||
|
||||
if (fclose(procf) == EOF) fatal(ihdr.name);
|
||||
}
|
||||
}
|
||||
|
||||
int rawfd; /* File descriptor to open device. */
|
||||
char *rawdev; /* Name of device. */
|
||||
|
||||
void readblock(off_t blk, char *buf, int block_size)
|
||||
/* For rawfs, so that it can read blocks. */
|
||||
{
|
||||
int n;
|
||||
|
||||
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|
||||
|| (n= read(rawfd, buf, block_size)) < 0
|
||||
) fatal(rawdev);
|
||||
|
||||
if (n < block_size) {
|
||||
fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void writeblock(off_t blk, char *buf, int block_size)
|
||||
/* Add a function to write blocks for local use. */
|
||||
{
|
||||
if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
|
||||
|| write(rawfd, buf, block_size) < 0
|
||||
) fatal(rawdev);
|
||||
}
|
||||
|
||||
int raw_install(char *file, off_t *start, off_t *len, int block_size)
|
||||
/* Copy bootcode or an image to the boot device at the given absolute disk
|
||||
* block number. This "raw" installation is used to place bootcode and
|
||||
* image on a disk without a filesystem to make a simple boot disk. Useful
|
||||
* in automated scripts for J. Random User.
|
||||
* Note: *len == 0 when an image is read. It is set right afterwards.
|
||||
*/
|
||||
{
|
||||
static char buf[_MAX_BLOCK_SIZE]; /* Nonvolatile block buffer. */
|
||||
FILE *f;
|
||||
off_t sec;
|
||||
unsigned long devsize;
|
||||
static int banner= 0;
|
||||
struct partition entry;
|
||||
|
||||
/* See if the device has a maximum size. */
|
||||
devsize= -1;
|
||||
if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
|
||||
|
||||
if ((f= fopen(file, "r")) == nil) fatal(file);
|
||||
|
||||
/* Copy sectors from file onto the boot device. */
|
||||
sec= *start;
|
||||
do {
|
||||
int off= sec % RATIO(BOOT_BLOCK_SIZE);
|
||||
|
||||
if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
|
||||
break;
|
||||
|
||||
if (sec >= devsize) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s can't be attached to %s\n",
|
||||
file, rawdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
|
||||
} while (++sec != *start + *len);
|
||||
|
||||
if (ferror(f)) fatal(file);
|
||||
(void) fclose(f);
|
||||
|
||||
/* Write a partial block, this may be the last image. */
|
||||
if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
if (!banner) {
|
||||
printf(" sector length\n");
|
||||
banner= 1;
|
||||
}
|
||||
*len= sec - *start;
|
||||
printf("%8ld%8ld %s\n", *start, *len, file);
|
||||
*start= sec;
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum howto { FS, BOOT };
|
||||
|
||||
void make_bootable(enum howto how, char *device, char *bootblock,
|
||||
char *bootcode, char **imagev)
|
||||
/* Install bootblock on the bootsector of device with the disk addresses to
|
||||
* bootcode patched into the data segment of bootblock. "How" tells if there
|
||||
* should or shoudn't be a file system on the disk. The images in the imagev
|
||||
* vector are added to the end of the device.
|
||||
*/
|
||||
{
|
||||
char buf[_MAX_BLOCK_SIZE + 256], *adrp, *parmp;
|
||||
struct fileaddr {
|
||||
off_t address;
|
||||
int count;
|
||||
} bootaddr[BOOT_MAX + 1], *bap= bootaddr;
|
||||
struct exec boothdr;
|
||||
struct image_header dummy;
|
||||
struct stat st;
|
||||
ino_t ino;
|
||||
off_t sector, max_sector;
|
||||
FILE *bootf;
|
||||
off_t addr, fssize, pos, len;
|
||||
char *labels, *label, *image;
|
||||
int nolabel;
|
||||
int block_size = 0;
|
||||
|
||||
/* Open device and set variables for readblock. */
|
||||
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
|
||||
|
||||
/* Read and check the superblock. */
|
||||
fssize= r_super(&block_size);
|
||||
|
||||
switch (how) {
|
||||
case FS:
|
||||
if (fssize == 0) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s is not a Minix file system\n",
|
||||
device);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case BOOT:
|
||||
if (fssize != 0) {
|
||||
int s;
|
||||
printf("%s contains a file system!\n", device);
|
||||
printf("Scribbling in 10 seconds");
|
||||
for (s= 0; s < 10; s++) {
|
||||
fputc('.', stdout);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
fssize= 1; /* Just a boot block. */
|
||||
}
|
||||
|
||||
if (how == FS) {
|
||||
/* See if the boot code can be found on the file system. */
|
||||
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
|
||||
if (errno != ENOENT) fatal(bootcode);
|
||||
}
|
||||
} else {
|
||||
/* Boot code must be attached at the end. */
|
||||
ino= 0;
|
||||
}
|
||||
|
||||
if (ino == 0) {
|
||||
/* For a raw installation, we need to copy the boot code onto
|
||||
* the device, so we need to look at the file to be copied.
|
||||
*/
|
||||
if (stat(bootcode, &st) < 0) fatal(bootcode);
|
||||
|
||||
if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
|
||||
} else {
|
||||
/* Boot code is present in the file system. */
|
||||
r_stat(ino, &st);
|
||||
|
||||
/* Get the header from the first block. */
|
||||
if ((addr= r_vir2abs((off_t) 0)) == 0) {
|
||||
boothdr.a_magic[0]= !A_MAGIC0;
|
||||
} else {
|
||||
readblock(addr, buf, block_size);
|
||||
memcpy(&boothdr, buf, sizeof(struct exec));
|
||||
}
|
||||
bootf= nil;
|
||||
dummy.process= boothdr;
|
||||
}
|
||||
/* See if it is an executable (read_header does the check). */
|
||||
read_header(0, bootcode, bootf, &dummy);
|
||||
boothdr= dummy.process;
|
||||
|
||||
if (bootf != nil) fclose(bootf);
|
||||
|
||||
/* Get all the sector addresses of the secondary boot code. */
|
||||
max_sector= (boothdr.a_hdrlen + boothdr.a_text
|
||||
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||
|
||||
if (max_sector > BOOT_MAX * RATIO(block_size)) {
|
||||
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Determine the addresses to the boot code to be patched into the
|
||||
* boot block.
|
||||
*/
|
||||
bap->count= 0; /* Trick to get the address recording going. */
|
||||
|
||||
for (sector= 0; sector < max_sector; sector++) {
|
||||
if (ino == 0) {
|
||||
addr= fssize + (sector / RATIO(block_size));
|
||||
} else
|
||||
if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
|
||||
fprintf(stderr, "installboot: %s has holes!\n",
|
||||
bootcode);
|
||||
exit(1);
|
||||
}
|
||||
addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
|
||||
|
||||
/* First address of the addresses array? */
|
||||
if (bap->count == 0) bap->address= addr;
|
||||
|
||||
/* Paste sectors together in a multisector read. */
|
||||
if (bap->address + bap->count == addr)
|
||||
bap->count++;
|
||||
else {
|
||||
/* New address. */
|
||||
bap++;
|
||||
bap->address= addr;
|
||||
bap->count= 1;
|
||||
}
|
||||
}
|
||||
(++bap)->count= 0; /* No more. */
|
||||
|
||||
/* Get the boot block and patch the pieces in. */
|
||||
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
|
||||
|
||||
read_header(0, bootblock, bootf, &dummy);
|
||||
boothdr= dummy.process;
|
||||
|
||||
if (boothdr.a_text + boothdr.a_data +
|
||||
4 * (bap - bootaddr) + 1 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: %s + addresses to %s don't fit in the boot sector\n",
|
||||
bootblock, bootcode);
|
||||
fprintf(stderr,
|
||||
"You can try copying/reinstalling %s to defragment it\n",
|
||||
bootcode);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* All checks out right. Read bootblock into the boot block! */
|
||||
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
|
||||
(void) fclose(bootf);
|
||||
|
||||
/* Patch the addresses in. */
|
||||
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
|
||||
for (bap= bootaddr; bap->count != 0; bap++) {
|
||||
*adrp++= bap->count;
|
||||
*adrp++= (bap->address >> 0) & 0xFF;
|
||||
*adrp++= (bap->address >> 8) & 0xFF;
|
||||
*adrp++= (bap->address >> 16) & 0xFF;
|
||||
}
|
||||
/* Zero count stops bootblock's reading loop. */
|
||||
*adrp++= 0;
|
||||
|
||||
if (bap > bootaddr+1) {
|
||||
printf("%s and %d addresses to %s patched into %s\n",
|
||||
bootblock, (int)(bap - bootaddr), bootcode, device);
|
||||
}
|
||||
|
||||
/* Boot block signature. */
|
||||
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
|
||||
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
|
||||
|
||||
/* Sector 2 of the boot block is used for boot parameters, initially
|
||||
* filled with null commands (newlines). Initialize it only if
|
||||
* necessary.
|
||||
*/
|
||||
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
|
||||
if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
|
||||
/* Param sector must be initialized. */
|
||||
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Offset to the end of the file system to add boot code and images. */
|
||||
pos= fssize * RATIO(block_size);
|
||||
|
||||
if (ino == 0) {
|
||||
/* Place the boot code onto the boot device. */
|
||||
len= max_sector;
|
||||
if (!raw_install(bootcode, &pos, &len, block_size)) {
|
||||
if (how == FS) {
|
||||
fprintf(stderr,
|
||||
"\t(Isn't there a copy of %s on %s that can be used?)\n",
|
||||
bootcode, device);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
parmp= buf + SECTOR_SIZE;
|
||||
nolabel= 0;
|
||||
|
||||
if (how == BOOT) {
|
||||
/* A boot only disk needs to have floppies swapped. */
|
||||
strcpy(parmp,
|
||||
"trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
while ((labels= *imagev++) != nil) {
|
||||
/* Place each kernel image on the boot device. */
|
||||
|
||||
if ((image= strchr(labels, ':')) != nil)
|
||||
*image++= 0;
|
||||
else {
|
||||
if (nolabel) {
|
||||
fprintf(stderr,
|
||||
"installboot: Only one image can be the default\n");
|
||||
exit(1);
|
||||
}
|
||||
nolabel= 1;
|
||||
image= labels;
|
||||
labels= nil;
|
||||
}
|
||||
len= 0;
|
||||
if (!raw_install(image, &pos, &len, block_size)) exit(1);
|
||||
|
||||
if (labels == nil) {
|
||||
/* Let this image be the default. */
|
||||
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
while (labels != nil) {
|
||||
/* Image is prefixed by a comma separated list of
|
||||
* labels. Define functions to select label and image.
|
||||
*/
|
||||
label= labels;
|
||||
if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
|
||||
|
||||
sprintf(parmp,
|
||||
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
|
||||
label,
|
||||
between('A', label[0], 'Z')
|
||||
? label[0]-'A'+'a' : label[0],
|
||||
label, pos-len, len, label);
|
||||
parmp+= strlen(parmp);
|
||||
}
|
||||
|
||||
if (parmp > buf + block_size) {
|
||||
fprintf(stderr,
|
||||
"installboot: Out of parameter space, too many images\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* Install boot block. */
|
||||
writeblock((off_t) BOOTBLOCK, buf, 1024);
|
||||
|
||||
if (pos > fssize * RATIO(block_size)) {
|
||||
/* Tell the total size of the data on the device. */
|
||||
printf("%16ld (%ld kb) total\n", pos,
|
||||
(pos + RATIO(block_size) - 1) / RATIO(block_size));
|
||||
}
|
||||
}
|
||||
|
||||
void install_master(char *device, char *masterboot, char **guide)
|
||||
/* Booting a hard disk is a two stage process: The master bootstrap in sector
|
||||
* 0 loads the bootstrap from sector 0 of the active partition which in turn
|
||||
* starts the operating system. This code installs such a master bootstrap
|
||||
* on a hard disk. If guide[0] is non-null then the master bootstrap is
|
||||
* guided into booting a certain device.
|
||||
*/
|
||||
{
|
||||
FILE *masf;
|
||||
unsigned long size;
|
||||
struct stat st;
|
||||
static char buf[_MAX_BLOCK_SIZE];
|
||||
|
||||
/* Open device. */
|
||||
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
|
||||
|
||||
/* Open the master boot code. */
|
||||
if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
|
||||
|
||||
/* See if the user is cloning a device. */
|
||||
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
|
||||
size= PARTPOS;
|
||||
else {
|
||||
/* Read and check header otherwise. */
|
||||
struct image_header ihdr;
|
||||
|
||||
read_header(1, masterboot, masf, &ihdr);
|
||||
size= ihdr.process.a_text + ihdr.process.a_data;
|
||||
}
|
||||
if (size > PARTPOS) {
|
||||
fprintf(stderr, "installboot: %s is too big\n", masterboot);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read the master boot block, patch it, write. */
|
||||
readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
|
||||
memset(buf, 0, PARTPOS);
|
||||
(void) bread(masf, masterboot, buf, size);
|
||||
|
||||
if (guide[0] != nil) {
|
||||
/* Fixate partition to boot. */
|
||||
char *keys= guide[0];
|
||||
char *logical= guide[1];
|
||||
size_t i;
|
||||
int logfd;
|
||||
u32_t offset;
|
||||
struct partition geometry;
|
||||
|
||||
/* A string of digits to be seen as keystrokes. */
|
||||
i= 0;
|
||||
do {
|
||||
if (!between('0', keys[i], '9')) {
|
||||
fprintf(stderr,
|
||||
"installboot: bad guide keys '%s'\n",
|
||||
keys);
|
||||
exit(1);
|
||||
}
|
||||
} while (keys[++i] != 0);
|
||||
|
||||
if (size + i + 1 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: not enough space after '%s' for '%s'\n",
|
||||
masterboot, keys);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(buf + size, keys, i);
|
||||
size += i;
|
||||
buf[size]= '\r';
|
||||
|
||||
if (logical != nil) {
|
||||
if ((logfd= open(logical, O_RDONLY)) < 0
|
||||
|| ioctl(logfd, DIOCGETP, &geometry) < 0
|
||||
) {
|
||||
fatal(logical);
|
||||
}
|
||||
offset= div64u(geometry.base, SECTOR_SIZE);
|
||||
if (size + 5 > PARTPOS) {
|
||||
fprintf(stderr,
|
||||
"installboot: not enough space "
|
||||
"after '%s' for '%s' and an offset "
|
||||
"to '%s'\n",
|
||||
masterboot, keys, logical);
|
||||
exit(1);
|
||||
}
|
||||
buf[size]= '#';
|
||||
memcpy(buf+size+1, &offset, 4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Install signature. */
|
||||
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
|
||||
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
|
||||
|
||||
writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: installboot -i(mage) image kernel mm fs ... init\n"
|
||||
" installboot -(e)x(tract) image\n"
|
||||
" installboot -d(evice) device bootblock boot [image ...]\n"
|
||||
" installboot -b(oot) device bootblock boot image ...\n"
|
||||
" installboot -m(aster) device masterboot [keys [logical]]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int isoption(char *option, char *test)
|
||||
/* Check if the option argument is equals "test". Also accept -i as short
|
||||
* for -image, and the special case -x for -extract.
|
||||
*/
|
||||
{
|
||||
if (strcmp(option, test) == 0) return 1;
|
||||
if (option[0] != '-' && strlen(option) != 2) return 0;
|
||||
if (option[1] == test[1]) return 1;
|
||||
if (option[1] == 'x' && test[1] == 'e') return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) usage();
|
||||
|
||||
if (argc >= 4 && isoption(argv[1], "-image")) {
|
||||
make_image(argv[2], argv + 3);
|
||||
} else
|
||||
if (argc == 3 && isoption(argv[1], "-extract")) {
|
||||
extract_image(argv[2]);
|
||||
} else
|
||||
if (argc >= 5 && isoption(argv[1], "-device")) {
|
||||
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
|
||||
} else
|
||||
if (argc >= 6 && isoption(argv[1], "-boot")) {
|
||||
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
|
||||
} else
|
||||
if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
|
||||
install_master(argv[2], argv[3], argv + 4);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
|
||||
*/
|
||||
261
boot/jumpboot.s
Executable file
261
boot/jumpboot.s
Executable file
@@ -0,0 +1,261 @@
|
||||
! jumpboot 1.0 - Jump to another bootstrap Author: Kees J. Bot
|
||||
! 14 Apr 1999
|
||||
!
|
||||
! This code may be placed into any free boot sector, like the first sector
|
||||
! of an extended partition, a file system partition other than the root,
|
||||
! or even the master bootstrap. It will load and run another bootstrap whose
|
||||
! disk, partition, and slice number (not necessarily all three) are patched
|
||||
! into this code by installboot. If the ALT key is held down when this code
|
||||
! is booted then you can type the disk, partition, and slice numbers manually.
|
||||
! The manual interface is default if no numbers are patched in by installboot.
|
||||
!
|
||||
|
||||
o32 = 0x66 ! This assembler doesn't know 386 extensions
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
PART_TABLE = 446 ! Location of partition table within master
|
||||
PENTRYSIZE = 16 ! Size of one partition table entry
|
||||
MAGIC = 510 ! Location of the AA55 magic number
|
||||
|
||||
! <ibm/partition.h>:
|
||||
MINIX_PART = 0x81
|
||||
sysind = 4
|
||||
lowsec = 8
|
||||
|
||||
|
||||
.text
|
||||
|
||||
! Find and load another bootstrap and jump to it.
|
||||
jumpboot:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
cli
|
||||
mov ss, ax ! ds = es = ss = Vector segment
|
||||
mov sp, #LOADOFF
|
||||
sti
|
||||
|
||||
! Move this code to safety, then jump to it.
|
||||
mov si, sp ! si = start of this code
|
||||
mov di, #BUFFER ! di = Buffer area
|
||||
mov cx, #512/2 ! One sector
|
||||
cld
|
||||
rep movs
|
||||
jmpf BUFFER+migrate, 0 ! To safety
|
||||
migrate:
|
||||
|
||||
mov bp, #BUFFER+guide ! Patched guiding characters
|
||||
altkey:
|
||||
movb ah, #0x02 ! Keyboard shift status
|
||||
int 0x16
|
||||
testb al, #0x08 ! Bit 3 = ALT key
|
||||
jz noalt ! ALT key pressed?
|
||||
again:
|
||||
mov bp, #zero ! Ignore patched stuff
|
||||
noalt:
|
||||
|
||||
! Follow guide characters to find the boot partition.
|
||||
call print
|
||||
.ascii "d?\b\0" ! Initial greeting
|
||||
|
||||
! Disk number?
|
||||
disk:
|
||||
movb dl, #0x80 - 0x30 ! Prepare to add an ASCII digit
|
||||
call getch ! Get number to tell which disk
|
||||
addb dl, al ! dl = 0x80 + (al - '0')
|
||||
jns n0nboot ! Result should be >= 0x80
|
||||
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
|
||||
cmpb (bp), #0x23 ! Next guide character is '#'?
|
||||
jne notlogical
|
||||
lea si, 1-lowsec(bp) ! Logical sector offset follows '#'
|
||||
notlogical:
|
||||
call load ! Load chosen sector of chosen disk
|
||||
cmpb (bp), #0x23
|
||||
je boot ! Run bootstrap if a logical is chosen
|
||||
|
||||
call print ! Intro to partition number
|
||||
.ascii "p?\b\0"
|
||||
|
||||
part:
|
||||
call getch ! Get character to tell partition
|
||||
call gettable ! Get partition table
|
||||
call sort ! Sort partition table
|
||||
call choose_load ! Compute chosen entry and load
|
||||
|
||||
cmpb sysind(si), #MINIX_PART ! Minix subpartition table possible?
|
||||
jne waitboot
|
||||
|
||||
call print ! Intro to slice number
|
||||
.ascii "s?\b\0"
|
||||
|
||||
slice:
|
||||
call getch ! Get character to tell slice
|
||||
call gettable ! Get partition table
|
||||
call choose_load ! Compute chosen entry and load
|
||||
|
||||
waitboot:
|
||||
call print ! Intro to nothing
|
||||
.ascii " ?\b\0"
|
||||
call getch ! Supposed to type RETURN now
|
||||
n0nboot:jmp nonboot ! Sorry, can't go further
|
||||
|
||||
! Get a character, either the patched-in, or one from the keyboard.
|
||||
getch:
|
||||
movb al, (bp) ! Get patched-in character
|
||||
testb al, al
|
||||
jz getkey
|
||||
inc bp
|
||||
jmp gotkey
|
||||
getkey: xorb ah, ah ! Wait for keypress
|
||||
int 0x16
|
||||
gotkey: testb dl, dl ! Ignore CR if disk number not yet set
|
||||
jns putch
|
||||
cmpb al, #0x0D ! Carriage return?
|
||||
je boot
|
||||
!jmp putch
|
||||
|
||||
! Print a character
|
||||
putch: movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
! Print a message.
|
||||
print: mov cx, si ! Save si
|
||||
pop si ! si = String following 'call print'
|
||||
prnext: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null marks end
|
||||
jz prdone
|
||||
call putch
|
||||
jmp prnext
|
||||
prdone: xchg si, cx ! Restore si
|
||||
jmp (cx) ! Continue after the string
|
||||
|
||||
! Return typed (or in patched data) means to run the bootstrap now in core!
|
||||
boot:
|
||||
call print ! Make line on screen look proper
|
||||
.ascii "\b \r\n\0"
|
||||
jmp LOADOFF-BUFFER ! Jump to LOADOFF
|
||||
|
||||
! Compute address of chosen partition entry from choice al into si, then
|
||||
! continue to load the boot sector of that partition.
|
||||
choose_load:
|
||||
subb al, #0x30 ! al -= '0'
|
||||
cmpb al, #4 ! Only four partitions
|
||||
ja n0nboot
|
||||
movb ah, #PENTRYSIZE
|
||||
mulb ah ! al *= PENTRYSIZE
|
||||
add ax, #BUFFER+PART_TABLE
|
||||
mov si, ax ! si = &part_table[al - '0']
|
||||
movb al, sysind(si) ! System indicator
|
||||
testb al, al ! Unused partition?
|
||||
jz n0nboot
|
||||
!jmp load ! Continue to load boot sector
|
||||
|
||||
! Load boot sector of the current partition.
|
||||
load:
|
||||
push dx ! Save drive code
|
||||
push es ! Next call sets es
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13
|
||||
pop es
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
movb al, cl ! al = cl = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov bx, ax ! bx = sectors per cylinder = heads * sectors
|
||||
mov ax, lowsec+0(si)
|
||||
mov dx, lowsec+2(si) ! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div bx ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb cl ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
pop dx ! Restore drive code in dl
|
||||
movb dh, al ! dh = al = head
|
||||
mov bx, #LOADOFF ! es:bx = where sector is loaded
|
||||
mov ax, #0x0201 ! ah = Code for read / al = one sector
|
||||
int 0x13
|
||||
jmp rdeval ! Evaluate read result
|
||||
bigdisk:
|
||||
mov bx, dx ! bx:ax = dx:ax = sector to read
|
||||
pop dx ! Restore drive code in dl
|
||||
push si ! Save si
|
||||
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
|
||||
mov 8(si), ax ! Starting block number = bx:ax
|
||||
mov 10(si), bx
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to partition entry
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jnc rdok
|
||||
rderr:
|
||||
call print
|
||||
.ascii "\r\nRead error\r\n\0"
|
||||
jmp again
|
||||
rdok:
|
||||
cmp LOADOFF+MAGIC, #0xAA55
|
||||
je sigok ! Signature ok?
|
||||
nonboot:
|
||||
call print
|
||||
.ascii "\r\nNot bootable\r\n\0"
|
||||
jmp again
|
||||
sigok:
|
||||
ret
|
||||
|
||||
! Get the partition table into my space.
|
||||
gettable:
|
||||
mov si, #LOADOFF+PART_TABLE
|
||||
mov di, #BUFFER+PART_TABLE
|
||||
mov cx, #4*PENTRYSIZE/2
|
||||
rep movs
|
||||
ret
|
||||
|
||||
! Sort the partition table.
|
||||
sort:
|
||||
mov cx, #4 ! Four times is enough to sort
|
||||
bubble: mov si, #BUFFER+PART_TABLE ! First table entry
|
||||
bubble1:lea di, PENTRYSIZE(si) ! Next entry
|
||||
cmpb sysind(si), ch ! Partition type, nonzero when in use
|
||||
jz exchg ! Unused entries sort to the end
|
||||
inuse: mov bx, lowsec+0(di)
|
||||
sub bx, lowsec+0(si) ! Compute di->lowsec - si->lowsec
|
||||
mov bx, lowsec+2(di)
|
||||
sbb bx, lowsec+2(si)
|
||||
jae order ! In order if si->lowsec <= di->lowsec
|
||||
exchg: movb bl, (si)
|
||||
xchgb bl, PENTRYSIZE(si) ! Exchange entries byte by byte
|
||||
movb (si), bl
|
||||
inc si
|
||||
cmp si, di
|
||||
jb exchg
|
||||
order: mov si, di
|
||||
cmp si, #BUFFER+PART_TABLE+3*PENTRYSIZE
|
||||
jb bubble1
|
||||
loop bubble
|
||||
ret
|
||||
|
||||
.data
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 1 ! Blocks to transfer (just one)
|
||||
.data2 LOADOFF ! Buffer address offset
|
||||
.data2 0 ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
zero: .data4 0 ! Starting block number high 32 bits
|
||||
|
||||
.align 2
|
||||
guide:
|
||||
! Guide characters and possibly a logical partition number patched here by
|
||||
! installboot, up to 6 bytes maximum.
|
||||
218
boot/masterboot.s
Executable file
218
boot/masterboot.s
Executable file
@@ -0,0 +1,218 @@
|
||||
! masterboot 2.0 - Master boot block code Author: Kees J. Bot
|
||||
!
|
||||
! This code may be placed in the first sector (the boot sector) of a floppy,
|
||||
! hard disk or hard disk primary partition. There it will perform the
|
||||
! following actions at boot time:
|
||||
!
|
||||
! - If the booted device is a hard disk and one of the partitions is active
|
||||
! then the active partition is booted.
|
||||
!
|
||||
! - Otherwise the next floppy or hard disk device is booted, trying them one
|
||||
! by one.
|
||||
!
|
||||
! To make things a little clearer, the boot path might be:
|
||||
! /dev/fd0 - Floppy disk containing data, tries fd1 then d0
|
||||
! [/dev/fd1] - Drive empty
|
||||
! /dev/c0d0 - Master boot block, selects active partition 2
|
||||
! /dev/c0d0p2 - Submaster, selects active subpartition 0
|
||||
! /dev/c0d0p2s0 - Minix bootblock, reads Boot Monitor /boot
|
||||
! Minix - Started by /boot from a kernel image in /minix
|
||||
|
||||
LOADOFF = 0x7C00 ! 0x0000:LOADOFF is where this code is loaded
|
||||
BUFFER = 0x0600 ! First free memory
|
||||
PART_TABLE = 446 ! Location of partition table within this code
|
||||
PENTRYSIZE = 16 ! Size of one partition table entry
|
||||
MAGIC = 510 ! Location of the AA55 magic number
|
||||
|
||||
! <ibm/partition>.h:
|
||||
bootind = 0
|
||||
sysind = 4
|
||||
lowsec = 8
|
||||
|
||||
|
||||
.text
|
||||
|
||||
! Find active (sub)partition, load its first sector, run it.
|
||||
|
||||
master:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
cli
|
||||
mov ss, ax ! ds = es = ss = Vector segment
|
||||
mov sp, #LOADOFF
|
||||
sti
|
||||
|
||||
! Copy this code to safety, then jump to it.
|
||||
mov si, sp ! si = start of this code
|
||||
push si ! Also where we'll return to eventually
|
||||
mov di, #BUFFER ! Buffer area
|
||||
mov cx, #512/2 ! One sector
|
||||
cld
|
||||
rep movs
|
||||
jmpf BUFFER+migrate, 0 ! To safety
|
||||
migrate:
|
||||
|
||||
! Find the active partition
|
||||
findactive:
|
||||
testb dl, dl
|
||||
jns nextdisk ! No bootable partitions on floppies
|
||||
mov si, #BUFFER+PART_TABLE
|
||||
find: cmpb sysind(si), #0 ! Partition type, nonzero when in use
|
||||
jz nextpart
|
||||
testb bootind(si), #0x80 ! Active partition flag in bit 7
|
||||
jz nextpart ! It's not active
|
||||
loadpart:
|
||||
call load ! Load partition bootstrap
|
||||
jc error1 ! Not supposed to fail
|
||||
bootstrap:
|
||||
ret ! Jump to the master bootstrap
|
||||
nextpart:
|
||||
add si, #PENTRYSIZE
|
||||
cmp si, #BUFFER+PART_TABLE+4*PENTRYSIZE
|
||||
jb find
|
||||
! No active partition, tell 'em
|
||||
call print
|
||||
.ascii "No active partition\0"
|
||||
jmp reboot
|
||||
|
||||
! There are no active partitions on this drive, try the next drive.
|
||||
nextdisk:
|
||||
incb dl ! Increment dl for the next drive
|
||||
testb dl, dl
|
||||
js nexthd ! Hard disk if negative
|
||||
int 0x11 ! Get equipment configuration
|
||||
shl ax, #1 ! Highest floppy drive # in bits 6-7
|
||||
shl ax, #1 ! Now in bits 0-1 of ah
|
||||
andb ah, #0x03 ! Extract bits
|
||||
cmpb dl, ah ! Must be dl <= ah for drive to exist
|
||||
ja nextdisk ! Otherwise try disk 0 eventually
|
||||
call load0 ! Read the next floppy bootstrap
|
||||
jc nextdisk ! It failed, next disk please
|
||||
ret ! Jump to the next master bootstrap
|
||||
nexthd: call load0 ! Read the hard disk bootstrap
|
||||
error1: jc error ! No disk?
|
||||
ret
|
||||
|
||||
|
||||
! Load sector 0 from the current device. It's either a floppy bootstrap or
|
||||
! a hard disk master bootstrap.
|
||||
load0:
|
||||
mov si, #BUFFER+zero-lowsec ! si = where lowsec(si) is zero
|
||||
!jmp load
|
||||
|
||||
! Load sector lowsec(si) from the current device. The obvious head, sector,
|
||||
! and cylinder numbers are ignored in favour of the more trustworthy absolute
|
||||
! start of partition.
|
||||
load:
|
||||
mov di, #3 ! Three retries for floppy spinup
|
||||
retry: push dx ! Save drive code
|
||||
push es
|
||||
push di ! Next call destroys es and di
|
||||
movb ah, #0x08 ! Code for drive parameters
|
||||
int 0x13
|
||||
pop di
|
||||
pop es
|
||||
andb cl, #0x3F ! cl = max sector number (1-origin)
|
||||
incb dh ! dh = 1 + max head number (0-origin)
|
||||
movb al, cl ! al = cl = sectors per track
|
||||
mulb dh ! dh = heads, ax = heads * sectors
|
||||
mov bx, ax ! bx = sectors per cylinder = heads * sectors
|
||||
mov ax, lowsec+0(si)
|
||||
mov dx, lowsec+2(si)! dx:ax = sector within drive
|
||||
cmp dx, #[1024*255*63-255]>>16 ! Near 8G limit?
|
||||
jae bigdisk
|
||||
div bx ! ax = cylinder, dx = sector within cylinder
|
||||
xchg ax, dx ! ax = sector within cylinder, dx = cylinder
|
||||
movb ch, dl ! ch = low 8 bits of cylinder
|
||||
divb cl ! al = head, ah = sector (0-origin)
|
||||
xorb dl, dl ! About to shift bits 8-9 of cylinder into dl
|
||||
shr dx, #1
|
||||
shr dx, #1 ! dl[6..7] = high cylinder
|
||||
orb dl, ah ! dl[0..5] = sector (0-origin)
|
||||
movb cl, dl ! cl[0..5] = sector, cl[6..7] = high cyl
|
||||
incb cl ! cl[0..5] = sector (1-origin)
|
||||
pop dx ! Restore drive code in dl
|
||||
movb dh, al ! dh = al = head
|
||||
mov bx, #LOADOFF ! es:bx = where sector is loaded
|
||||
mov ax, #0x0201 ! Code for read, just one sector
|
||||
int 0x13 ! Call the BIOS for a read
|
||||
jmp rdeval ! Evaluate read result
|
||||
bigdisk:
|
||||
mov bx, dx ! bx:ax = dx:ax = sector to read
|
||||
pop dx ! Restore drive code in dl
|
||||
push si ! Save si
|
||||
mov si, #BUFFER+ext_rw ! si = extended read/write parameter packet
|
||||
mov 8(si), ax ! Starting block number = bx:ax
|
||||
mov 10(si), bx
|
||||
movb ah, #0x42 ! Extended read
|
||||
int 0x13
|
||||
pop si ! Restore si to point to partition entry
|
||||
!jmp rdeval
|
||||
rdeval:
|
||||
jnc rdok ! Read succeeded
|
||||
cmpb ah, #0x80 ! Disk timed out? (Floppy drive empty)
|
||||
je rdbad
|
||||
dec di
|
||||
jl rdbad ! Retry count expired
|
||||
xorb ah, ah
|
||||
int 0x13 ! Reset
|
||||
jnc retry ! Try again
|
||||
rdbad: stc ! Set carry flag
|
||||
ret
|
||||
rdok: cmp LOADOFF+MAGIC, #0xAA55
|
||||
jne nosig ! Error if signature wrong
|
||||
ret ! Return with carry still clear
|
||||
nosig: call print
|
||||
.ascii "Not bootable\0"
|
||||
jmp reboot
|
||||
|
||||
! A read error occurred, complain and hang
|
||||
error:
|
||||
mov si, #LOADOFF+errno+1
|
||||
prnum: movb al, ah ! Error number in ah
|
||||
andb al, #0x0F ! Low 4 bits
|
||||
cmpb al, #10 ! A-F?
|
||||
jb digit ! 0-9!
|
||||
addb al, #7 ! 'A' - ':'
|
||||
digit: addb (si), al ! Modify '0' in string
|
||||
dec si
|
||||
movb cl, #4 ! Next 4 bits
|
||||
shrb ah, cl
|
||||
jnz prnum ! Again if digit > 0
|
||||
call print
|
||||
.ascii "Read error "
|
||||
errno: .ascii "00\0"
|
||||
!jmp reboot
|
||||
|
||||
reboot:
|
||||
call print
|
||||
.ascii ". Hit any key to reboot.\0"
|
||||
xorb ah, ah ! Wait for keypress
|
||||
int 0x16
|
||||
call print
|
||||
.ascii "\r\n\0"
|
||||
int 0x19
|
||||
|
||||
! Print a message.
|
||||
print: pop si ! si = String following 'call print'
|
||||
prnext: lodsb ! al = *si++ is char to be printed
|
||||
testb al, al ! Null marks end
|
||||
jz prdone
|
||||
movb ah, #0x0E ! Print character in teletype mode
|
||||
mov bx, #0x0001 ! Page 0, foreground color
|
||||
int 0x10
|
||||
jmp prnext
|
||||
prdone: jmp (si) ! Continue after the string
|
||||
|
||||
.data
|
||||
|
||||
! Extended read/write commands require a parameter packet.
|
||||
ext_rw:
|
||||
.data1 0x10 ! Length of extended r/w packet
|
||||
.data1 0 ! Reserved
|
||||
.data2 1 ! Blocks to transfer (just one)
|
||||
.data2 LOADOFF ! Buffer address offset
|
||||
.data2 0 ! Buffer address segment
|
||||
.data4 0 ! Starting block number low 32 bits (tbfi)
|
||||
zero: .data4 0 ! Starting block number high 32 bits
|
||||
137
boot/mkfhead.s
Executable file
137
boot/mkfhead.s
Executable file
@@ -0,0 +1,137 @@
|
||||
! Mkfhead.s - DOS & BIOS support for mkfile.c Author: Kees J. Bot
|
||||
! 9 May 1998
|
||||
!
|
||||
! This file contains the startup and low level support for the MKFILE.COM
|
||||
! utility. See doshead.ack.s for more comments on .COM files.
|
||||
!
|
||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
||||
.sect .text
|
||||
|
||||
.define _PSP
|
||||
_PSP:
|
||||
.space 256 ! Program Segment Prefix
|
||||
|
||||
mkfile:
|
||||
cld ! C compiler wants UP
|
||||
xor ax, ax ! Zero
|
||||
mov di, _edata ! Start of bss is at end of data
|
||||
mov cx, _end ! End of bss (begin of heap)
|
||||
sub cx, di ! Number of bss bytes
|
||||
shr cx, 1 ! Number of words
|
||||
rep stos ! Clear bss
|
||||
|
||||
xor cx, cx ! cx = argc
|
||||
xor bx, bx
|
||||
push bx ! argv[argc] = NULL
|
||||
movb bl, (_PSP+0x80) ! Argument byte count
|
||||
0: movb _PSP+0x81(bx), ch ! Null terminate
|
||||
dec bx
|
||||
js 9f
|
||||
cmpb _PSP+0x81(bx), 0x20 ! Whitespace?
|
||||
jbe 0b
|
||||
1: dec bx ! One argument character
|
||||
js 2f
|
||||
cmpb _PSP+0x81(bx), 0x20 ! More argument characters?
|
||||
ja 1b
|
||||
2: lea ax, _PSP+0x81+1(bx) ! Address of argument
|
||||
push ax ! argv[n]
|
||||
inc cx ! argc++;
|
||||
test bx, bx
|
||||
jns 0b ! More arguments?
|
||||
9: movb _PSP+0x81(bx), ch ! Make a null string
|
||||
lea ax, _PSP+0x81(bx)
|
||||
push ax ! to use as argv[0]
|
||||
inc cx ! Final value of argc
|
||||
mov ax, sp
|
||||
push ax ! argv
|
||||
push cx ! argc
|
||||
call _main ! main(argc, argv)
|
||||
push ax
|
||||
call _exit ! exit(main(argc, argv))
|
||||
|
||||
! int creat(const char *path, mode_t mode)
|
||||
! Create a file with the old creat() call.
|
||||
.define _creat
|
||||
_creat:
|
||||
mov bx, sp
|
||||
mov dx, 2(bx) ! Filename
|
||||
xor cx, cx ! Ignore mode, always read-write
|
||||
movb ah, 0x3C ! "CREAT"
|
||||
dos: int 0x21 ! ax = creat(path, 0666);
|
||||
jc seterrno
|
||||
ret
|
||||
|
||||
seterrno:
|
||||
mov (_errno), ax ! Set errno to the DOS error code
|
||||
mov ax, -1
|
||||
cwd ! return -1L;
|
||||
ret
|
||||
|
||||
! int open(const char *path, int oflag)
|
||||
! Open a file with the oldfashioned two-argument open() call.
|
||||
.define _open
|
||||
_open:
|
||||
mov bx, sp
|
||||
mov dx, 2(bx) ! Filename
|
||||
movb al, 4(bx) ! O_RDONLY, O_WRONLY, O_RDWR
|
||||
movb ah, 0x3D ! "OPEN"
|
||||
jmp dos
|
||||
|
||||
! int close(int fd)
|
||||
! Close an open file.
|
||||
.define _close
|
||||
_close:
|
||||
mov bx, sp
|
||||
mov bx, 2(bx) ! bx = file handle
|
||||
movb ah, 0x3E ! "CLOSE"
|
||||
jmp dos
|
||||
|
||||
! void exit(int status)
|
||||
! void _exit(int status)
|
||||
! Return to DOS.
|
||||
.define _exit, __exit, ___exit
|
||||
_exit:
|
||||
__exit:
|
||||
___exit:
|
||||
pop ax
|
||||
pop ax ! al = status
|
||||
movb ah, 0x4C ! "EXIT"
|
||||
int 0x21
|
||||
hlt
|
||||
|
||||
! ssize_t read(int fd, void *buf, size_t n)
|
||||
! Read bytes from an open file.
|
||||
.define _read
|
||||
_read:
|
||||
mov bx, sp
|
||||
mov cx, 6(bx)
|
||||
mov dx, 4(bx)
|
||||
mov bx, 2(bx)
|
||||
movb ah, 0x3F ! "READ"
|
||||
jmp dos
|
||||
|
||||
! ssize_t write(int fd, const void *buf, size_t n)
|
||||
! Write bytes to an open file.
|
||||
.define _write
|
||||
_write:
|
||||
mov bx, sp
|
||||
mov cx, 6(bx)
|
||||
mov dx, 4(bx)
|
||||
mov bx, 2(bx)
|
||||
movb ah, 0x40 ! "WRITE"
|
||||
jmp dos
|
||||
|
||||
! off_t lseek(int fd, off_t offset, int whence)
|
||||
! Set file position for read or write.
|
||||
.define _lseek
|
||||
_lseek:
|
||||
mov bx, sp
|
||||
movb al, 8(bx) ! SEEK_SET, SEEK_CUR, SEEK_END
|
||||
mov dx, 4(bx)
|
||||
mov cx, 6(bx) ! cx:dx = offset
|
||||
mov bx, 2(bx)
|
||||
movb ah, 0x42 ! "LSEEK"
|
||||
jmp dos
|
||||
|
||||
!
|
||||
! $PchId: mkfhead.ack.s,v 1.3 1999/01/14 21:17:06 philip Exp $
|
||||
180
boot/mkfile.c
Executable file
180
boot/mkfile.c
Executable file
@@ -0,0 +1,180 @@
|
||||
/* mkfile 1.0 - create a file under DOS for use as a Minix "disk".
|
||||
* Author: Kees J. Bot
|
||||
* 9 May 1998
|
||||
*/
|
||||
#define nil 0
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Stuff normally found in <unistd.h>, <errno.h>, etc. */
|
||||
extern int errno;
|
||||
int creat(const char *file, int mode);
|
||||
int open(const char *file, int oflag);
|
||||
off_t lseek(int fd, off_t offset, int whence);
|
||||
ssize_t write(int fd, const char *buf, size_t len);
|
||||
void exit(int status);
|
||||
int printf(const char *fmt, ...);
|
||||
|
||||
#define O_WRONLY 1
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_END 2
|
||||
|
||||
/* Kernel printf requires a putk() function. */
|
||||
int putk(int c)
|
||||
{
|
||||
char ch = c;
|
||||
|
||||
if (c == 0) return;
|
||||
if (c == '\n') putk('\r');
|
||||
(void) write(2, &ch, 1);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: mkfile <size>[gmk] <file>\n"
|
||||
"(Example sizes, all 50 meg: 52428800, 51200k, 50m)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *strerror(int err)
|
||||
/* Translate some DOS error numbers to text. */
|
||||
{
|
||||
static struct errlist {
|
||||
int err;
|
||||
char *what;
|
||||
} errlist[] = {
|
||||
{ 0, "No error" },
|
||||
{ 1, "Function number invalid" },
|
||||
{ 2, "File not found" },
|
||||
{ 3, "Path not found" },
|
||||
{ 4, "Too many open files" },
|
||||
{ 5, "Access denied" },
|
||||
{ 6, "Invalid handle" },
|
||||
{ 12, "Access code invalid" },
|
||||
{ 39, "Insufficient disk space" },
|
||||
};
|
||||
struct errlist *ep;
|
||||
static char unknown[]= "Error 65535";
|
||||
unsigned e;
|
||||
char *p;
|
||||
|
||||
for (ep= errlist; ep < errlist + sizeof(errlist)/sizeof(errlist[0]);
|
||||
ep++) {
|
||||
if (ep->err == err) return ep->what;
|
||||
}
|
||||
p= unknown + sizeof(unknown) - 1;
|
||||
e= err;
|
||||
do *--p= '0' + (e % 10); while ((e /= 10) > 0);
|
||||
strcpy(unknown + 6, p);
|
||||
return unknown;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
static char buf[512];
|
||||
unsigned long size, mul;
|
||||
off_t offset;
|
||||
char *cp;
|
||||
int fd;
|
||||
char *file;
|
||||
|
||||
if (argc != 3) usage();
|
||||
|
||||
cp= argv[1];
|
||||
size= 0;
|
||||
while ((unsigned) (*cp - '0') < 10) {
|
||||
unsigned d= *cp++ - '0';
|
||||
if (size <= (ULONG_MAX-9) / 10) {
|
||||
size= size * 10 + d;
|
||||
} else {
|
||||
size= ULONG_MAX;
|
||||
}
|
||||
}
|
||||
if (cp == argv[1]) usage();
|
||||
while (*cp != 0) {
|
||||
mul = 1;
|
||||
switch (*cp++) {
|
||||
case 'G':
|
||||
case 'g': mul *= 1024;
|
||||
case 'M':
|
||||
case 'm': mul *= 1024;
|
||||
case 'K':
|
||||
case 'k': mul *= 1024;
|
||||
case 'B':
|
||||
case 'b': break;
|
||||
default: usage();
|
||||
}
|
||||
if (size <= ULONG_MAX / mul) {
|
||||
size *= mul;
|
||||
} else {
|
||||
size= ULONG_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 1024L*1024*1024) {
|
||||
printf("mkfile: A file size over 1G is a bit too much\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Open existing file, or create a new file. */
|
||||
file= argv[2];
|
||||
if ((fd= open(file, O_WRONLY)) < 0) {
|
||||
if (errno == 2) {
|
||||
fd= creat(file, 0666);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
printf("mkfile: Can't open %s: %s\n", file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* How big is the file now? */
|
||||
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
|
||||
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (offset == 0 && size == 0) exit(0); /* Huh? */
|
||||
|
||||
/* Write the first bit if the file is zero length. This is necessary
|
||||
* to circumvent a DOS bug by extending a new file by lseek. We also
|
||||
* want to make sure there are zeros in the first sector.
|
||||
*/
|
||||
if (offset == 0) {
|
||||
if (write(fd, buf, sizeof(buf)) == -1) {
|
||||
printf("mkfile: Can't write to %s: %s\n",
|
||||
file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Seek to the required size and write 0 bytes to extend/truncate the
|
||||
* file to that size.
|
||||
*/
|
||||
if (lseek(fd, size, SEEK_SET) == -1) {
|
||||
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (write(fd, buf, 0) == -1) {
|
||||
printf("mkfile: Can't write to %s: %s\n",
|
||||
file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Did the file become the required size? */
|
||||
if ((offset= lseek(fd, 0, SEEK_END)) == -1) {
|
||||
printf("mkfile: Can't seek in %s: %s\n", file, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (offset != size) {
|
||||
printf("mkfile: Failed to extend %s. Disk full?\n", file);
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: mkfile.c,v 1.4 2000/08/13 22:06:40 philip Exp $
|
||||
*/
|
||||
329
boot/rawfs.c
Executable file
329
boot/rawfs.c
Executable file
@@ -0,0 +1,329 @@
|
||||
/* rawfs.c - Raw Minix file system support. Author: Kees J. Bot
|
||||
* 23 Dec 1991
|
||||
* Based on readfs by Paul Polderman
|
||||
*/
|
||||
#define nil 0
|
||||
#define _POSIX_SOURCE 1
|
||||
#define _MINIX 1
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
#include <minix/type.h>
|
||||
#include <servers/fs/const.h>
|
||||
#include <servers/fs/type.h>
|
||||
#include <servers/fs/buf.h>
|
||||
#include <servers/fs/super.h>
|
||||
#include <servers/fs/inode.h>
|
||||
#include "rawfs.h"
|
||||
|
||||
void readblock(off_t blockno, char *buf, int);
|
||||
|
||||
/* The following code handles two file system types: Version 1 with small
|
||||
* inodes and 16-bit disk addresses and Version 2 with big inodes and 32-bit
|
||||
* disk addresses.
|
||||
#ifdef FLEX
|
||||
* To make matters worse, Minix-vmd knows about the normal Unix Version 7
|
||||
* directories and directories with flexible entries.
|
||||
#endif
|
||||
*/
|
||||
|
||||
/* File system parameters. */
|
||||
static unsigned nr_dzones; /* Fill these in after reading superblock. */
|
||||
static unsigned nr_indirects;
|
||||
static unsigned inodes_per_block;
|
||||
static int block_size;
|
||||
#ifdef FLEX
|
||||
#include <dirent.h>
|
||||
#define direct _v7_direct
|
||||
#else
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#if __minix_vmd
|
||||
static struct v12_super_block super; /* Superblock of file system */
|
||||
#define s_log_zone_size s_dummy /* Zones are obsolete. */
|
||||
#else
|
||||
static struct super_block super; /* Superblock of file system */
|
||||
#define SUPER_V1 SUPER_MAGIC /* V1 magic has a weird name. */
|
||||
#endif
|
||||
|
||||
static struct inode curfil; /* Inode of file under examination */
|
||||
static char indir[_MAX_BLOCK_SIZE]; /* Single indirect block. */
|
||||
static char dindir[_MAX_BLOCK_SIZE]; /* Double indirect block. */
|
||||
static char dirbuf[_MAX_BLOCK_SIZE]; /* Scratch/Directory block. */
|
||||
#define scratch dirbuf
|
||||
|
||||
static block_t a_indir, a_dindir; /* Addresses of the indirects. */
|
||||
static off_t dirpos; /* Reading pos in a dir. */
|
||||
|
||||
#define fsbuf(b) (* (struct buf *) (b))
|
||||
|
||||
#define zone_shift (super.s_log_zone_size) /* zone to block ratio */
|
||||
|
||||
off_t r_super(int *bs)
|
||||
/* Initialize variables, return size of file system in blocks,
|
||||
* (zero on error).
|
||||
*/
|
||||
{
|
||||
/* Read superblock. (The superblock is always at 1kB offset,
|
||||
* that's why we lie to readblock and say the block size is 1024
|
||||
* and we want block number 1 (the 'second block', at offset 1kB).)
|
||||
*/
|
||||
readblock(1, scratch, 1024);
|
||||
|
||||
memcpy(&super, scratch, sizeof(super));
|
||||
|
||||
/* Is it really a MINIX file system ? */
|
||||
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
||||
if(super.s_magic == SUPER_V2)
|
||||
super.s_block_size = 1024;
|
||||
*bs = block_size = super.s_block_size;
|
||||
if(block_size < _MIN_BLOCK_SIZE ||
|
||||
block_size > _MAX_BLOCK_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
nr_dzones= V2_NR_DZONES;
|
||||
nr_indirects= V2_INDIRECTS(block_size);
|
||||
inodes_per_block= V2_INODES_PER_BLOCK(block_size);
|
||||
return (off_t) super.s_zones << zone_shift;
|
||||
} else
|
||||
if (super.s_magic == SUPER_V1) {
|
||||
*bs = block_size = 1024;
|
||||
nr_dzones= V1_NR_DZONES;
|
||||
nr_indirects= V1_INDIRECTS;
|
||||
inodes_per_block= V1_INODES_PER_BLOCK;
|
||||
return (off_t) super.s_nzones << zone_shift;
|
||||
} else {
|
||||
/* Filesystem not recognized as Minix. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void r_stat(Ino_t inum, struct stat *stp)
|
||||
/* Return information about a file like stat(2) and remember it. */
|
||||
{
|
||||
block_t block;
|
||||
block_t ino_block;
|
||||
ino_t ino_offset;
|
||||
|
||||
/* Calculate start of i-list */
|
||||
block = START_BLOCK + super.s_imap_blocks + super.s_zmap_blocks;
|
||||
|
||||
/* Calculate block with inode inum */
|
||||
ino_block = ((inum - 1) / inodes_per_block);
|
||||
ino_offset = ((inum - 1) % inodes_per_block);
|
||||
block += ino_block;
|
||||
|
||||
/* Fetch the block */
|
||||
readblock(block, scratch, block_size);
|
||||
|
||||
if (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3) {
|
||||
d2_inode *dip;
|
||||
int i;
|
||||
|
||||
dip= &fsbuf(scratch).b_v2_ino[ino_offset];
|
||||
|
||||
curfil.i_mode= dip->d2_mode;
|
||||
curfil.i_nlinks= dip->d2_nlinks;
|
||||
curfil.i_uid= dip->d2_uid;
|
||||
curfil.i_gid= dip->d2_gid;
|
||||
curfil.i_size= dip->d2_size;
|
||||
curfil.i_atime= dip->d2_atime;
|
||||
curfil.i_mtime= dip->d2_mtime;
|
||||
curfil.i_ctime= dip->d2_ctime;
|
||||
for (i= 0; i < V2_NR_TZONES; i++)
|
||||
curfil.i_zone[i]= dip->d2_zone[i];
|
||||
} else {
|
||||
d1_inode *dip;
|
||||
int i;
|
||||
|
||||
dip= &fsbuf(scratch).b_v1_ino[ino_offset];
|
||||
|
||||
curfil.i_mode= dip->d1_mode;
|
||||
curfil.i_nlinks= dip->d1_nlinks;
|
||||
curfil.i_uid= dip->d1_uid;
|
||||
curfil.i_gid= dip->d1_gid;
|
||||
curfil.i_size= dip->d1_size;
|
||||
curfil.i_atime= dip->d1_mtime;
|
||||
curfil.i_mtime= dip->d1_mtime;
|
||||
curfil.i_ctime= dip->d1_mtime;
|
||||
for (i= 0; i < V1_NR_TZONES; i++)
|
||||
curfil.i_zone[i]= dip->d1_zone[i];
|
||||
}
|
||||
curfil.i_dev= -1; /* Can't fill this in alas. */
|
||||
curfil.i_num= inum;
|
||||
|
||||
stp->st_dev= curfil.i_dev;
|
||||
stp->st_ino= curfil.i_num;
|
||||
stp->st_mode= curfil.i_mode;
|
||||
stp->st_nlink= curfil.i_nlinks;
|
||||
stp->st_uid= curfil.i_uid;
|
||||
stp->st_gid= curfil.i_gid;
|
||||
stp->st_rdev= (dev_t) curfil.i_zone[0];
|
||||
stp->st_size= curfil.i_size;
|
||||
stp->st_atime= curfil.i_atime;
|
||||
stp->st_mtime= curfil.i_mtime;
|
||||
stp->st_ctime= curfil.i_ctime;
|
||||
|
||||
a_indir= a_dindir= 0;
|
||||
dirpos= 0;
|
||||
}
|
||||
|
||||
ino_t r_readdir(char *name)
|
||||
/* Read next directory entry at "dirpos" from file "curfil". */
|
||||
{
|
||||
ino_t inum= 0;
|
||||
int blkpos;
|
||||
struct direct *dp;
|
||||
|
||||
if (!S_ISDIR(curfil.i_mode)) { errno= ENOTDIR; return -1; }
|
||||
|
||||
if(!block_size) { errno = 0; return -1; }
|
||||
|
||||
while (inum == 0 && dirpos < curfil.i_size) {
|
||||
if ((blkpos= (int) (dirpos % block_size)) == 0) {
|
||||
/* Need to fetch a new directory block. */
|
||||
|
||||
readblock(r_vir2abs(dirpos / block_size), dirbuf, block_size);
|
||||
}
|
||||
#ifdef FLEX
|
||||
if (super.s_flags & S_FLEX) {
|
||||
struct _fl_direct *dp;
|
||||
|
||||
dp= (struct _fl_direct *) (dirbuf + blkpos);
|
||||
if ((inum= dp->d_ino) != 0) strcpy(name, dp->d_name);
|
||||
|
||||
dirpos+= (1 + dp->d_extent) * FL_DIR_ENTRY_SIZE;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
/* Let dp point to the next entry. */
|
||||
dp= (struct direct *) (dirbuf + blkpos);
|
||||
|
||||
if ((inum= dp->d_ino) != 0) {
|
||||
/* This entry is occupied, return name. */
|
||||
strncpy(name, dp->d_name, sizeof(dp->d_name));
|
||||
name[sizeof(dp->d_name)]= 0;
|
||||
}
|
||||
dirpos+= DIR_ENTRY_SIZE;
|
||||
}
|
||||
return inum;
|
||||
}
|
||||
|
||||
off_t r_vir2abs(off_t virblk)
|
||||
/* Translate a block number in a file to an absolute disk block number.
|
||||
* Returns 0 for a hole and -1 if block is past end of file.
|
||||
*/
|
||||
{
|
||||
block_t b= virblk;
|
||||
zone_t zone, ind_zone;
|
||||
block_t z, zone_index;
|
||||
int i;
|
||||
|
||||
if(!block_size) return -1;
|
||||
|
||||
/* Check if virblk within file. */
|
||||
if (virblk * block_size >= curfil.i_size) return -1;
|
||||
|
||||
/* Calculate zone in which the datablock number is contained */
|
||||
zone = (zone_t) (b >> zone_shift);
|
||||
|
||||
/* Calculate index of the block number in the zone */
|
||||
zone_index = b - ((block_t) zone << zone_shift);
|
||||
|
||||
/* Go get the zone */
|
||||
if (zone < (zone_t) nr_dzones) { /* direct block */
|
||||
zone = curfil.i_zone[(int) zone];
|
||||
z = ((block_t) zone << zone_shift) + zone_index;
|
||||
return z;
|
||||
}
|
||||
|
||||
/* The zone is not a direct one */
|
||||
zone -= (zone_t) nr_dzones;
|
||||
|
||||
/* Is it single indirect ? */
|
||||
if (zone < (zone_t) nr_indirects) { /* single indirect block */
|
||||
ind_zone = curfil.i_zone[nr_dzones];
|
||||
} else { /* double indirect block */
|
||||
/* Fetch the double indirect block */
|
||||
if ((ind_zone = curfil.i_zone[nr_dzones + 1]) == 0) return 0;
|
||||
|
||||
z = (block_t) ind_zone << zone_shift;
|
||||
if (a_dindir != z) {
|
||||
readblock(z, dindir, block_size);
|
||||
a_dindir= z;
|
||||
}
|
||||
/* Extract the indirect zone number from it */
|
||||
zone -= (zone_t) nr_indirects;
|
||||
|
||||
i = zone / (zone_t) nr_indirects;
|
||||
ind_zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
||||
? fsbuf(dindir).b_v2_ind[i]
|
||||
: fsbuf(dindir).b_v1_ind[i];
|
||||
zone %= (zone_t) nr_indirects;
|
||||
}
|
||||
if (ind_zone == 0) return 0;
|
||||
|
||||
/* Extract the datablock number from the indirect zone */
|
||||
z = (block_t) ind_zone << zone_shift;
|
||||
if (a_indir != z) {
|
||||
readblock(z, indir, block_size);
|
||||
a_indir= z;
|
||||
}
|
||||
zone = (super.s_magic == SUPER_V2 || super.s_magic == SUPER_V3)
|
||||
? fsbuf(indir).b_v2_ind[(int) zone]
|
||||
: fsbuf(indir).b_v1_ind[(int) zone];
|
||||
|
||||
/* Calculate absolute datablock number */
|
||||
z = ((block_t) zone << zone_shift) + zone_index;
|
||||
return z;
|
||||
}
|
||||
|
||||
ino_t r_lookup(Ino_t cwd, char *path)
|
||||
/* Translates a pathname to an inode number. This is just a nice utility
|
||||
* function, it only needs r_stat and r_readdir.
|
||||
*/
|
||||
{
|
||||
char name[NAME_MAX+1], r_name[NAME_MAX+1];
|
||||
char *n;
|
||||
struct stat st;
|
||||
ino_t ino;
|
||||
|
||||
ino= path[0] == '/' ? ROOT_INO : cwd;
|
||||
|
||||
for (;;) {
|
||||
if (ino == 0) {
|
||||
errno= ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*path == '/') path++;
|
||||
|
||||
if (*path == 0) return ino;
|
||||
|
||||
r_stat(ino, &st);
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
errno= ENOTDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
n= name;
|
||||
while (*path != 0 && *path != '/')
|
||||
if (n < name + NAME_MAX) *n++ = *path++;
|
||||
*n= 0;
|
||||
|
||||
while ((ino= r_readdir(r_name)) != 0
|
||||
&& strcmp(name, r_name) != 0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* $PchId: rawfs.c,v 1.8 1999/11/05 23:14:15 philip Exp $
|
||||
*/
|
||||
43
boot/rawfs.h
Executable file
43
boot/rawfs.h
Executable file
@@ -0,0 +1,43 @@
|
||||
/* rawfs.h - Raw Minix file system support. Author: Kees J. Bot
|
||||
*
|
||||
* off_t r_super(int *block_size);
|
||||
* Initialize variables, returns the size of a valid Minix
|
||||
* file system blocks, but zero on error.
|
||||
*
|
||||
* void r_stat(ino_t file, struct stat *stp);
|
||||
* Return information about a file like stat(2) and
|
||||
* remembers file for the next two calls.
|
||||
*
|
||||
* off_t r_vir2abs(off_t virblockno);
|
||||
* Translate virtual block number in file to absolute
|
||||
* disk block number. Returns 0 if the file contains
|
||||
* a hole, or -1 if the block lies past the end of file.
|
||||
*
|
||||
* ino_t r_readdir(char *name);
|
||||
* Return next directory entry or 0 if there are no more.
|
||||
* Returns -1 and sets errno on error.
|
||||
*
|
||||
* ino_t r_lookup(ino_t cwd, char *path);
|
||||
* A utility function that translates a pathname to an
|
||||
* inode number. It starts from directory "cwd" unless
|
||||
* path starts with a '/', then from ROOT_INO.
|
||||
* Returns 0 and sets errno on error.
|
||||
*
|
||||
* One function needs to be provided by the outside world:
|
||||
*
|
||||
* void readblock(off_t blockno, char *buf, int block_size);
|
||||
* Read a block into the buffer. Outside world handles
|
||||
* errors.
|
||||
*/
|
||||
|
||||
#define ROOT_INO ((ino_t) 1) /* Inode nr of root dir. */
|
||||
|
||||
off_t r_super(int *);
|
||||
void r_stat(Ino_t file, struct stat *stp);
|
||||
off_t r_vir2abs(off_t virblockno);
|
||||
ino_t r_readdir(char *name);
|
||||
ino_t r_lookup(Ino_t cwd, char *path);
|
||||
|
||||
/*
|
||||
* $PchId: rawfs.h,v 1.4 1996/04/19 08:16:36 philip Exp $
|
||||
*/
|
||||
@@ -1,4 +0,0 @@
|
||||
SCRIPTS= DESCRIBE.sh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
@@ -1,4 +0,0 @@
|
||||
SCRIPTS= MAKEDEV.sh
|
||||
MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
74
commands/Makefile
Normal file → Executable file
74
commands/Makefile
Normal file → Executable file
@@ -1,44 +1,40 @@
|
||||
# Makefile for commands.
|
||||
|
||||
.include <bsd.own.mk>
|
||||
MAKE = exec make -$(MAKEFLAGS)
|
||||
BZIP2=bzip2-1.0.3
|
||||
|
||||
SUBDIR= add_route arp ash at awk \
|
||||
backup badblocks banner basename \
|
||||
btrace cal calendar \
|
||||
cat cawf cd cdprobe checkhier cpp \
|
||||
chmod chown chroot ci cksum cleantmp clear cmp co \
|
||||
comm compress cp crc cron crontab cut \
|
||||
dd decomp16 DESCRIBE dev2name devsize df dhcpd \
|
||||
dhrystone diff dirname diskctl du dumpcore \
|
||||
ed eject elvis env expand factor fbdctl file \
|
||||
find finger fingerd fix fold format fortune fsck.mfs \
|
||||
ftp101 gcore gcov-pull getty grep head hexdump host \
|
||||
hostaddr id ifconfig ifdef install \
|
||||
intr ipcrm ipcs irdpd isoread join kill last leave \
|
||||
less lex loadkeys loadramdisk logger login look lp \
|
||||
lpd ls lspci mail make MAKEDEV \
|
||||
mdb mesg mined mkfifo mkfs.mfs mknod \
|
||||
mkproto modem mount mt netconf newroot nice acknm nohup \
|
||||
nonamed od paste patch pax \
|
||||
ping postinstall poweroff pr prep printf printroot \
|
||||
profile progressbar proto pr_routes ps pwd pwdauth \
|
||||
ramdisk rarpd rawspeed rcp rdate readall readclock \
|
||||
reboot remsync rev rget rlogin rlogind \
|
||||
rotate rsh rshd sed service setup shar acksize \
|
||||
sleep slip sort spell split srccrc \
|
||||
stty su sum svclog swifi sync synctree sysenv \
|
||||
syslogd tail tar tcpd tcpdp tcpstat tee telnet \
|
||||
telnetd term termcap tget time touch tr \
|
||||
truncate tsort tty udpstat umount uname unexpand \
|
||||
unstack update uud uue version vol wc \
|
||||
whereis which who write writeisofs fetch \
|
||||
xargs yacc yes zdump zmodem pkgin_cd \
|
||||
mktemp worldstone updateboot
|
||||
SMALLPROGRAMS=`arch` aal advent ash autil awk bc byacc cawf cron de dhcpd dis88 elle elvis ftp ftpd200 httpd ibm indent m4 make mdb mined patch pax ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap zmodem
|
||||
|
||||
.if ${ARCH} == "i386"
|
||||
SUBDIR+= atnormalize dosread fdisk loadfont \
|
||||
autopart part partition playwave \
|
||||
recwave repartition screendump
|
||||
.endif
|
||||
usage:
|
||||
@echo "Usage: make all # Compile all commands" >&2
|
||||
@echo " make install # Install the result (run as bin!)" >&2
|
||||
@echo " make clean # Delete .o files and other junk" >&2
|
||||
@echo " make big # Compile all big commands" >&2
|
||||
@echo " make biginstall # Install all big commands" >&2
|
||||
@echo " make small # Install all small commands" >&2
|
||||
@echo " make smallinstall # Install all small commands" >&2
|
||||
@echo " "
|
||||
@echo "big compiles the commands the require large compiler sizes."
|
||||
@echo "small compiles the rest. all compiles all."
|
||||
@false
|
||||
|
||||
all: small big
|
||||
|
||||
install: biginstall smallinstall
|
||||
|
||||
big:
|
||||
cd $(BZIP2) && /bin/sh build build
|
||||
|
||||
biginstall: big
|
||||
cd $(BZIP2) && make install
|
||||
|
||||
clean::
|
||||
cd $(BZIP2) && make clean
|
||||
for p in $(SMALLPROGRAMS); do ( cd $$p && make clean ); done
|
||||
|
||||
small::
|
||||
set -e; for p in $(SMALLPROGRAMS); do ( cd $$p && make all ); done
|
||||
|
||||
smallinstall::
|
||||
set -e; for p in $(SMALLPROGRAMS); do ( cd $$p && make install ); done
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
CPPFLAGS+= -D_MINIX -D_NETBSD_SOURCE -D_MINIX_COMPAT
|
||||
LDADD+= -lminlib -lcompat_minix -lasyn -lterminfo
|
||||
BINDIR?=/usr/bin
|
||||
56
commands/aal/Makefile
Executable file
56
commands/aal/Makefile
Executable file
@@ -0,0 +1,56 @@
|
||||
# Makefile for aal
|
||||
|
||||
CC=exec cc
|
||||
CFLAGS=-I. -wo -DAAL -DSTB -DNDEBUG -DDISTRIBUTION -D_POSIX_SOURCE -D_MINIX
|
||||
LDFLAGS=-i
|
||||
|
||||
all: aal
|
||||
|
||||
OFILES= archiver.o \
|
||||
print.o \
|
||||
rd.o \
|
||||
rd_arhdr.o \
|
||||
rd_unsig2.o \
|
||||
sprint.o \
|
||||
wr_arhdr.o \
|
||||
wr_bytes.o \
|
||||
wr_int2.o \
|
||||
wr_long.o \
|
||||
wr_ranlib.o \
|
||||
format.o \
|
||||
rd_bytes.o \
|
||||
system.o \
|
||||
write.o \
|
||||
long2str.o
|
||||
|
||||
aal: $(OFILES)
|
||||
$(CC) $(LDFLAGS) -o aal $(OFILES)
|
||||
install -S 512k $@
|
||||
|
||||
install: /usr/bin/aal /usr/bin/ar
|
||||
|
||||
/usr/bin/aal: aal
|
||||
install -cs -o bin aal $@
|
||||
|
||||
/usr/bin/ar: /usr/bin/aal
|
||||
install -l $? $@
|
||||
|
||||
archiver.o:
|
||||
print.o:
|
||||
rd.o:
|
||||
rd_arhdr.o:
|
||||
rd_unsig2.o:
|
||||
sprint.o:
|
||||
wr_arhdr.o:
|
||||
wr_bytes.o:
|
||||
wr_int2.o:
|
||||
wr_long.o:
|
||||
wr_ranlib.o:
|
||||
format.o:
|
||||
rd_bytes.o:
|
||||
system.o:
|
||||
write.o:
|
||||
long2str.o:
|
||||
|
||||
clean:
|
||||
rm -f *.o core *.bak aal
|
||||
25
commands/aal/arch.h
Executable file
25
commands/aal/arch.h
Executable file
@@ -0,0 +1,25 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_H_INCLUDED
|
||||
#define __ARCH_H_INCLUDED
|
||||
|
||||
#define ARMAG 0177545
|
||||
#define AALMAG 0177454
|
||||
|
||||
struct ar_hdr {
|
||||
char ar_name[14];
|
||||
long ar_date;
|
||||
char ar_uid;
|
||||
char ar_gid;
|
||||
short ar_mode;
|
||||
long ar_size;
|
||||
};
|
||||
|
||||
#define AR_TOTAL 26
|
||||
#define AR_SIZE 22
|
||||
|
||||
#endif /* __ARCH_H_INCLUDED */
|
||||
800
commands/aal/archiver.c
Executable file
800
commands/aal/archiver.c
Executable file
@@ -0,0 +1,800 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* ar - archiver Author: Michiel Huisjes */
|
||||
/* Made into arch/aal by Ceriel Jacobs
|
||||
*/
|
||||
|
||||
static char RcsId[] = "$Header$";
|
||||
|
||||
/*
|
||||
* Usage: [arch|aal] [adprtvx] archive [file] ...
|
||||
* v: verbose
|
||||
* x: extract
|
||||
* a: append
|
||||
* r: replace (append when not in archive)
|
||||
* d: delete
|
||||
* t: print contents of archive
|
||||
* p: print named files
|
||||
* l: temporaries in current directory instead of /usr/tmp
|
||||
* c: don't give "create" message
|
||||
* u: replace only if dated later than member in archive
|
||||
#ifdef DISTRIBUTION
|
||||
* D: make distribution: use distr_time, uid=2, gid=2, mode=0644
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef S_IREAD
|
||||
#define S_IREAD S_IRUSR
|
||||
#endif
|
||||
#ifndef S_IWRITE
|
||||
#define S_IWRITE S_IWUSR
|
||||
#endif
|
||||
#ifndef S_IEXEC
|
||||
#define S_IEXEC S_IXUSR
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <arch.h>
|
||||
#ifdef AAL
|
||||
#include <ranlib.h>
|
||||
#include <out.h>
|
||||
#define MAGIC_NUMBER AALMAG
|
||||
long offset;
|
||||
struct ranlib *tab;
|
||||
unsigned int tnum = 0;
|
||||
char *tstrtab;
|
||||
unsigned int tssiz = 0;
|
||||
char *malloc(), *realloc(), *strcpy(), *strncpy();
|
||||
long time();
|
||||
unsigned int tabsz, strtabsz;
|
||||
#else
|
||||
#define MAGIC_NUMBER ARMAG
|
||||
#endif
|
||||
long lseek();
|
||||
|
||||
#define odd(nr) (nr & 01)
|
||||
#define even(nr) (odd(nr) ? nr + 1 : nr)
|
||||
|
||||
typedef char BOOL;
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define READ 0
|
||||
#define APPEND 2
|
||||
#define CREATE 1
|
||||
|
||||
#define MEMBER struct ar_hdr
|
||||
|
||||
#define NIL_PTR ((char *) 0)
|
||||
#define NIL_MEM ((MEMBER *) 0)
|
||||
#define NIL_LONG ((long *) 0)
|
||||
|
||||
#define IO_SIZE (10 * 1024)
|
||||
|
||||
#define equal(str1, str2) (!strncmp((str1), (str2), 14))
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (m & S_IFDIR) /* is a directory */
|
||||
#endif
|
||||
|
||||
BOOL verbose;
|
||||
BOOL app_fl;
|
||||
BOOL ex_fl;
|
||||
BOOL show_fl;
|
||||
BOOL pr_fl;
|
||||
BOOL rep_fl;
|
||||
BOOL del_fl;
|
||||
BOOL nocr_fl;
|
||||
BOOL local_fl;
|
||||
BOOL update_fl;
|
||||
#ifdef DISTRIBUTION
|
||||
BOOL distr_fl;
|
||||
long distr_time;
|
||||
#endif
|
||||
|
||||
int ar_fd;
|
||||
|
||||
char io_buffer[IO_SIZE];
|
||||
|
||||
char *progname;
|
||||
|
||||
char temp_buf[32];
|
||||
char *temp_arch = &temp_buf[0];
|
||||
extern char *mktemp();
|
||||
extern char *ctime();
|
||||
|
||||
usage()
|
||||
{
|
||||
error(TRUE, "usage: %s %s archive [file] ...\n",
|
||||
progname,
|
||||
#ifdef AAL
|
||||
"[acdrtxvlu]"
|
||||
#else
|
||||
"[acdprtxvlu]"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
/*VARARGS2*/
|
||||
error(quit, str1, str2, str3, str4)
|
||||
BOOL quit;
|
||||
char *str1, *str2, *str3, *str4;
|
||||
{
|
||||
char errbuf[256];
|
||||
|
||||
sprint(errbuf, str1, str2, str3, str4);
|
||||
write(2, errbuf, strlen(errbuf));
|
||||
if (quit) {
|
||||
unlink(temp_arch);
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
char *basename(path)
|
||||
char *path;
|
||||
{
|
||||
register char *ptr = path;
|
||||
register char *last = NIL_PTR;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr == '/')
|
||||
last = ptr;
|
||||
ptr++;
|
||||
}
|
||||
if (last == NIL_PTR)
|
||||
return path;
|
||||
if (*(last + 1) == '\0') {
|
||||
*last = '\0';
|
||||
return basename(path);
|
||||
}
|
||||
return last + 1;
|
||||
}
|
||||
|
||||
extern unsigned int rd_unsigned2();
|
||||
|
||||
open_archive(name, mode)
|
||||
register char *name;
|
||||
register int mode;
|
||||
{
|
||||
unsigned short magic = 0;
|
||||
int fd;
|
||||
|
||||
if (mode == CREATE) {
|
||||
if ((fd = creat(name, 0666)) < 0)
|
||||
error(TRUE, "cannot creat %s\n", name);
|
||||
magic = MAGIC_NUMBER;
|
||||
wr_int2(fd, magic);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if ((fd = open(name, mode)) < 0) {
|
||||
if (mode == APPEND) {
|
||||
close(open_archive(name, CREATE));
|
||||
if (!nocr_fl) error(FALSE, "%s: creating %s\n", progname, name);
|
||||
return open_archive(name, APPEND);
|
||||
}
|
||||
error(TRUE, "cannot open %s\n", name);
|
||||
}
|
||||
lseek(fd, 0L, 0);
|
||||
magic = rd_unsigned2(fd);
|
||||
if (magic != AALMAG && magic != ARMAG)
|
||||
error(TRUE, "%s is not in ar format\n", name);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#if __STDC__
|
||||
void catch(int sig)
|
||||
#else
|
||||
catch()
|
||||
#endif
|
||||
{
|
||||
unlink(temp_arch);
|
||||
_exit (2);
|
||||
}
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register char *ptr;
|
||||
int needs_arg = 0;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 3)
|
||||
usage();
|
||||
|
||||
for (ptr = argv[1]; *ptr; ptr++) {
|
||||
switch (*ptr) {
|
||||
case 't' :
|
||||
show_fl = TRUE;
|
||||
break;
|
||||
case 'v' :
|
||||
verbose = TRUE;
|
||||
break;
|
||||
case 'x' :
|
||||
ex_fl = TRUE;
|
||||
break;
|
||||
case 'a' :
|
||||
needs_arg = 1;
|
||||
app_fl = TRUE;
|
||||
break;
|
||||
case 'c' :
|
||||
nocr_fl = TRUE;
|
||||
break;
|
||||
#ifndef AAL
|
||||
case 'p' :
|
||||
needs_arg = 1;
|
||||
pr_fl = TRUE;
|
||||
break;
|
||||
#endif
|
||||
case 'd' :
|
||||
needs_arg = 1;
|
||||
del_fl = TRUE;
|
||||
break;
|
||||
case 'r' :
|
||||
needs_arg = 1;
|
||||
rep_fl = TRUE;
|
||||
break;
|
||||
case 'l' :
|
||||
local_fl = TRUE;
|
||||
break;
|
||||
case 'u' :
|
||||
update_fl = TRUE;
|
||||
break;
|
||||
#ifdef DISTRIBUTION
|
||||
case 'D' :
|
||||
distr_fl = TRUE;
|
||||
break;
|
||||
#endif
|
||||
default :
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_arg && argc <= 3)
|
||||
usage();
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
struct stat statbuf;
|
||||
|
||||
stat(progname, &statbuf);
|
||||
distr_time = statbuf.st_mtime;
|
||||
}
|
||||
#endif
|
||||
if (local_fl) strcpy(temp_arch, "ar.XXXXXX");
|
||||
else strcpy(temp_arch, "/usr/tmp/ar.XXXXXX");
|
||||
|
||||
if (app_fl + ex_fl + del_fl + rep_fl + show_fl + pr_fl != 1)
|
||||
usage();
|
||||
|
||||
if (update_fl && !rep_fl)
|
||||
usage();
|
||||
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
mktemp(temp_arch);
|
||||
}
|
||||
#ifdef AAL
|
||||
tab = (struct ranlib *) malloc(512 * sizeof(struct ranlib));
|
||||
tstrtab = malloc(4096);
|
||||
if (!tab || !tstrtab) error(TRUE,"Out of core\n");
|
||||
tabsz = 512;
|
||||
strtabsz = 4096;
|
||||
#endif
|
||||
|
||||
signal(SIGINT, catch);
|
||||
get(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MEMBER *
|
||||
get_member()
|
||||
{
|
||||
static MEMBER member;
|
||||
|
||||
again:
|
||||
if (rd_arhdr(ar_fd, &member) == 0)
|
||||
return NIL_MEM;
|
||||
if (member.ar_size < 0) {
|
||||
error(TRUE, "archive has member with negative size\n");
|
||||
}
|
||||
#ifdef AAL
|
||||
if (equal(SYMDEF, member.ar_name)) {
|
||||
lseek(ar_fd, member.ar_size, 1);
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return &member;
|
||||
}
|
||||
|
||||
char *get_mode();
|
||||
|
||||
get(argc, argv)
|
||||
int argc;
|
||||
register char *argv[];
|
||||
{
|
||||
register MEMBER *member;
|
||||
int i = 0;
|
||||
int temp_fd, read_chars;
|
||||
|
||||
ar_fd = open_archive(argv[2], (show_fl || pr_fl || ex_fl) ? READ : APPEND);
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
)
|
||||
temp_fd = open_archive(temp_arch, CREATE);
|
||||
while ((member = get_member()) != NIL_MEM) {
|
||||
if (argc > 3) {
|
||||
for (i = 3; i < argc; i++) {
|
||||
if (equal(basename(argv[i]), member->ar_name))
|
||||
break;
|
||||
}
|
||||
if (i == argc || app_fl) {
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
#ifdef AAL
|
||||
if (i != argc) {
|
||||
print("%s: already in archive\n", argv[i]);
|
||||
argv[i] = "";
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(temp_fd, member);
|
||||
copy_member(member, ar_fd, temp_fd, 0);
|
||||
}
|
||||
else {
|
||||
#ifndef AAL
|
||||
if (app_fl && i != argc) {
|
||||
print("%s: already in archive\n", argv[i]);
|
||||
argv[i] = "";
|
||||
}
|
||||
#endif
|
||||
lseek(ar_fd, even(member->ar_size),1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ex_fl || pr_fl)
|
||||
extract(member);
|
||||
else {
|
||||
if (rep_fl) {
|
||||
int isold = 0;
|
||||
if(update_fl) {
|
||||
struct stat status;
|
||||
if (stat(argv[i], &status) >= 0) {
|
||||
if(status.st_mtime <= member->ar_date)
|
||||
isold = 1;
|
||||
}
|
||||
}
|
||||
if(!isold)
|
||||
add(argv[i], temp_fd, "r - %s\n");
|
||||
else {
|
||||
wr_arhdr(temp_fd, member);
|
||||
copy_member(member, ar_fd, temp_fd, 0);
|
||||
if(verbose)
|
||||
show("r - %s (old)\n", member->ar_name);
|
||||
}
|
||||
}
|
||||
else if (show_fl) {
|
||||
char buf[sizeof(member->ar_name) + 2];
|
||||
register char *p = buf, *q = member->ar_name;
|
||||
|
||||
while (q <= &member->ar_name[sizeof(member->ar_name)-1] && *q) {
|
||||
*p++ = *q++;
|
||||
}
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
if (verbose) {
|
||||
char *mode = get_mode(member->ar_mode);
|
||||
char *date = ctime(&(member->ar_date));
|
||||
|
||||
*(date + 16) = '\0';
|
||||
*(date + 24) = '\0';
|
||||
|
||||
print("%s%3u/%u%7ld %s %s %s",
|
||||
mode,
|
||||
(unsigned) (member->ar_uid & 0377),
|
||||
(unsigned) (member->ar_gid & 0377),
|
||||
member->ar_size,
|
||||
date+4,
|
||||
date+20,
|
||||
buf);
|
||||
}
|
||||
else print(buf);
|
||||
}
|
||||
else if (del_fl)
|
||||
show("d - %s\n", member->ar_name);
|
||||
lseek(ar_fd, even(member->ar_size), 1);
|
||||
}
|
||||
argv[i] = "";
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
for (i = 3; i < argc; i++)
|
||||
if (argv[i][0] != '\0') {
|
||||
#ifndef AAL
|
||||
if (app_fl)
|
||||
add(argv[i], ar_fd, "a - %s\n");
|
||||
else
|
||||
#endif
|
||||
if (rep_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
)
|
||||
add(argv[i], temp_fd, "a - %s\n");
|
||||
else {
|
||||
print("%s: not found\n", argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rep_fl || del_fl
|
||||
#ifdef AAL
|
||||
|| app_fl
|
||||
#endif
|
||||
) {
|
||||
signal(SIGINT, SIG_IGN);
|
||||
close(ar_fd);
|
||||
close(temp_fd);
|
||||
ar_fd = open_archive(argv[2], CREATE);
|
||||
temp_fd = open_archive(temp_arch, APPEND);
|
||||
#ifdef AAL
|
||||
write_symdef();
|
||||
#endif
|
||||
while ((read_chars = read(temp_fd, io_buffer, IO_SIZE)) > 0)
|
||||
mwrite(ar_fd, io_buffer, read_chars);
|
||||
close(temp_fd);
|
||||
unlink(temp_arch);
|
||||
}
|
||||
close(ar_fd);
|
||||
}
|
||||
|
||||
add(name, fd, mess)
|
||||
char *name;
|
||||
int fd;
|
||||
char *mess;
|
||||
{
|
||||
static MEMBER member;
|
||||
register int read_chars;
|
||||
struct stat status;
|
||||
int src_fd;
|
||||
|
||||
if (stat(name, &status) < 0) {
|
||||
error(FALSE, "cannot find %s\n", name);
|
||||
return;
|
||||
}
|
||||
else if (S_ISDIR(status.st_mode)) {
|
||||
error(FALSE, "%s is a directory (ignored)\n", name);
|
||||
return;
|
||||
}
|
||||
else if ((src_fd = open(name, 0)) < 0) {
|
||||
error(FALSE, "cannot open %s\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy (member.ar_name, basename (name), sizeof(member.ar_name));
|
||||
member.ar_uid = status.st_uid;
|
||||
member.ar_gid = status.st_gid;
|
||||
member.ar_mode = status.st_mode;
|
||||
member.ar_date = status.st_mtime;
|
||||
member.ar_size = status.st_size;
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
member.ar_uid = 2;
|
||||
member.ar_gid = 2;
|
||||
member.ar_mode = 0644;
|
||||
member.ar_date = distr_time;
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(fd, &member);
|
||||
#ifdef AAL
|
||||
do_object(src_fd, member.ar_size);
|
||||
lseek(src_fd, 0L, 0);
|
||||
offset += AR_TOTAL + even(member.ar_size);
|
||||
#endif
|
||||
while (status.st_size > 0) {
|
||||
int x = IO_SIZE;
|
||||
|
||||
read_chars = x;
|
||||
if (status.st_size < x) {
|
||||
x = status.st_size;
|
||||
read_chars = x;
|
||||
status.st_size = 0;
|
||||
x = even(x);
|
||||
}
|
||||
else status.st_size -= x;
|
||||
if (read(src_fd, io_buffer, read_chars) != read_chars) {
|
||||
error(FALSE,"%s seems to shrink\n", name);
|
||||
break;
|
||||
}
|
||||
mwrite(fd, io_buffer, x);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
show(mess, member.ar_name);
|
||||
close(src_fd);
|
||||
}
|
||||
|
||||
extract(member)
|
||||
register MEMBER *member;
|
||||
{
|
||||
int fd = 1;
|
||||
char buf[sizeof(member->ar_name) + 1];
|
||||
|
||||
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
||||
buf[sizeof(member->ar_name)] = 0;
|
||||
if (pr_fl == FALSE && (fd = creat(buf, 0666)) < 0) {
|
||||
error(FALSE, "cannot create %s\n", buf);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
if (pr_fl == FALSE) show("x - %s\n", buf);
|
||||
else show("\n<%s>\n\n", buf);
|
||||
}
|
||||
|
||||
copy_member(member, ar_fd, fd, 1);
|
||||
|
||||
if (fd >= 0 && fd != 1)
|
||||
close(fd);
|
||||
if (pr_fl == FALSE) chmod(buf, member->ar_mode);
|
||||
}
|
||||
|
||||
copy_member(member, from, to, extracting)
|
||||
register MEMBER *member;
|
||||
int from, to;
|
||||
{
|
||||
register int rest;
|
||||
long mem_size = member->ar_size;
|
||||
BOOL is_odd = odd(mem_size) ? TRUE : FALSE;
|
||||
|
||||
#ifdef AAL
|
||||
if (! extracting) {
|
||||
long pos = lseek(from, 0L, 1);
|
||||
|
||||
do_object(from, mem_size);
|
||||
offset += AR_TOTAL + even(mem_size);
|
||||
lseek(from, pos, 0);
|
||||
}
|
||||
#endif
|
||||
do {
|
||||
rest = mem_size > (long) IO_SIZE ? IO_SIZE : (int) mem_size;
|
||||
if (read(from, io_buffer, rest) != rest) {
|
||||
char buf[sizeof(member->ar_name) + 1];
|
||||
|
||||
strncpy(buf, member->ar_name, sizeof(member->ar_name));
|
||||
buf[sizeof(member->ar_name)] = 0;
|
||||
error(TRUE, "read error on %s\n", buf);
|
||||
}
|
||||
if (to >= 0) mwrite(to, io_buffer, rest);
|
||||
mem_size -= (long) rest;
|
||||
} while (mem_size > 0L);
|
||||
|
||||
if (is_odd) {
|
||||
lseek(from, 1L, 1);
|
||||
if (to >= 0 && ! extracting)
|
||||
lseek(to, 1L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
get_mode(mode)
|
||||
register int mode;
|
||||
{
|
||||
static char mode_buf[11];
|
||||
register int tmp = mode;
|
||||
int i;
|
||||
|
||||
mode_buf[9] = ' ';
|
||||
for (i = 0; i < 3; i++) {
|
||||
mode_buf[i * 3] = (tmp & S_IREAD) ? 'r' : '-';
|
||||
mode_buf[i * 3 + 1] = (tmp & S_IWRITE) ? 'w' : '-';
|
||||
mode_buf[i * 3 + 2] = (tmp & S_IEXEC) ? 'x' : '-';
|
||||
tmp <<= 3;
|
||||
}
|
||||
if (mode & S_ISUID)
|
||||
mode_buf[2] = 's';
|
||||
if (mode & S_ISGID)
|
||||
mode_buf[5] = 's';
|
||||
return mode_buf;
|
||||
}
|
||||
|
||||
wr_fatal()
|
||||
{
|
||||
error(TRUE, "write error\n");
|
||||
}
|
||||
|
||||
rd_fatal()
|
||||
{
|
||||
error(TRUE, "read error\n");
|
||||
}
|
||||
|
||||
mwrite(fd, address, bytes)
|
||||
int fd;
|
||||
register char *address;
|
||||
register int bytes;
|
||||
{
|
||||
if (write(fd, address, bytes) != bytes)
|
||||
error(TRUE, "write error\n");
|
||||
}
|
||||
|
||||
show(s, name)
|
||||
char *s, *name;
|
||||
{
|
||||
MEMBER x;
|
||||
char buf[sizeof(x.ar_name)+1];
|
||||
register char *p = buf, *q = name;
|
||||
|
||||
while (q <= &name[sizeof(x.ar_name)-1] && *q) *p++ = *q++;
|
||||
*p++ = '\0';
|
||||
print(s, buf);
|
||||
}
|
||||
|
||||
#ifdef AAL
|
||||
/*
|
||||
* Write out the ranlib table: first 4 bytes telling how many ranlib structs
|
||||
* there are, followed by the ranlib structs,
|
||||
* then 4 bytes giving the size of the string table, followed by the string
|
||||
* table itself.
|
||||
*/
|
||||
write_symdef()
|
||||
{
|
||||
register struct ranlib *ran;
|
||||
register int i;
|
||||
register long delta;
|
||||
MEMBER arbuf;
|
||||
|
||||
if (odd(tssiz))
|
||||
tstrtab[tssiz++] = '\0';
|
||||
for (i = 0; i < sizeof(arbuf.ar_name); i++)
|
||||
arbuf.ar_name[i] = '\0';
|
||||
strcpy(arbuf.ar_name, SYMDEF);
|
||||
arbuf.ar_size = 4 + 2 * 4 * (long)tnum + 4 + (long)tssiz;
|
||||
time(&arbuf.ar_date);
|
||||
arbuf.ar_uid = getuid();
|
||||
arbuf.ar_gid = getgid();
|
||||
arbuf.ar_mode = 0444;
|
||||
#ifdef DISTRIBUTION
|
||||
if (distr_fl) {
|
||||
arbuf.ar_uid = 2;
|
||||
arbuf.ar_gid = 2;
|
||||
arbuf.ar_date = distr_time;
|
||||
}
|
||||
#endif
|
||||
wr_arhdr(ar_fd,&arbuf);
|
||||
wr_long(ar_fd, (long) tnum);
|
||||
/*
|
||||
* Account for the space occupied by the magic number
|
||||
* and the ranlib table.
|
||||
*/
|
||||
delta = 2 + AR_TOTAL + arbuf.ar_size;
|
||||
for (ran = tab; ran < &tab[tnum]; ran++) {
|
||||
ran->ran_pos += delta;
|
||||
}
|
||||
|
||||
wr_ranlib(ar_fd, tab, (long) tnum);
|
||||
wr_long(ar_fd, (long) tssiz);
|
||||
wr_bytes(ar_fd, tstrtab, (long) tssiz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether the bytes in `buf' form a good object header.
|
||||
* The header is put in `headp'.
|
||||
*/
|
||||
int
|
||||
is_outhead(headp)
|
||||
register struct outhead *headp;
|
||||
{
|
||||
|
||||
return !BADMAGIC(*headp) && headp->oh_nname != 0;
|
||||
}
|
||||
|
||||
do_object(f, size)
|
||||
long size;
|
||||
{
|
||||
struct outhead headbuf;
|
||||
|
||||
if (size < SZ_HEAD) {
|
||||
/* It can't be an object file. */
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Read a header to see if it is an object file.
|
||||
*/
|
||||
if (! rd_fdopen(f)) {
|
||||
rd_fatal();
|
||||
}
|
||||
rd_ohead(&headbuf);
|
||||
if (!is_outhead(&headbuf)) {
|
||||
return;
|
||||
}
|
||||
do_names(&headbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* First skip the names and read in the string table, then seek back to the
|
||||
* name table and read and write the names one by one. Update the ranlib table
|
||||
* accordingly.
|
||||
*/
|
||||
do_names(headp)
|
||||
struct outhead *headp;
|
||||
{
|
||||
register char *strings;
|
||||
register int nnames = headp->oh_nname;
|
||||
#define NNAMES 100
|
||||
struct outname namebuf[NNAMES];
|
||||
long xxx = OFF_CHAR(*headp);
|
||||
|
||||
if ( headp->oh_nchar != (unsigned int)headp->oh_nchar ||
|
||||
(strings = malloc((unsigned int)headp->oh_nchar)) == (char *)0
|
||||
) {
|
||||
error(TRUE, "string table too big\n");
|
||||
}
|
||||
rd_string(strings, headp->oh_nchar);
|
||||
while (nnames) {
|
||||
int i = nnames >= NNAMES ? NNAMES : nnames;
|
||||
register struct outname *p = namebuf;
|
||||
|
||||
nnames -= i;
|
||||
rd_name(namebuf, i);
|
||||
while (i--) {
|
||||
long off = p->on_foff - xxx;
|
||||
if (p->on_foff == (long)0) {
|
||||
p++;
|
||||
continue; /* An unrecognizable name. */
|
||||
}
|
||||
p->on_mptr = strings + off;
|
||||
/*
|
||||
* Only enter names that are exported and are really
|
||||
* defined. Also enter common names. Note, that
|
||||
* this might cause problems when the name is really
|
||||
* defined in a later file, with a value != 0.
|
||||
* However, this problem also exists on the Unix
|
||||
* ranlib archives.
|
||||
*/
|
||||
if ( (p->on_type & S_EXT) &&
|
||||
(p->on_type & S_TYP) != S_UND
|
||||
)
|
||||
enter_name(p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
enter_name(namep)
|
||||
struct outname *namep;
|
||||
{
|
||||
register char *cp;
|
||||
|
||||
if (tnum >= tabsz) {
|
||||
tab = (struct ranlib *)
|
||||
realloc((char *) tab, (tabsz += 512) * sizeof(struct ranlib));
|
||||
if (! tab) error(TRUE, "Out of core\n");
|
||||
}
|
||||
tab[tnum].ran_off = tssiz;
|
||||
tab[tnum].ran_pos = offset;
|
||||
|
||||
for (cp = namep->on_mptr;; cp++) {
|
||||
if (tssiz >= strtabsz) {
|
||||
tstrtab = realloc(tstrtab, (strtabsz += 4096));
|
||||
if (! tstrtab) error(TRUE, "string table overflow\n");
|
||||
}
|
||||
tstrtab[tssiz++] = *cp;
|
||||
if (!*cp) break;
|
||||
}
|
||||
tnum++;
|
||||
}
|
||||
#endif AAL
|
||||
3
commands/aal/build
Executable file
3
commands/aal/build
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
make clean
|
||||
make && make install
|
||||
9
commands/aal/byte_order.h
Executable file
9
commands/aal/byte_order.h
Executable file
@@ -0,0 +1,9 @@
|
||||
#if defined(mc68020) || defined(mc68000) || defined(sparc)
|
||||
#define BYTES_REVERSED 1
|
||||
#define WORDS_REVERSED 1
|
||||
#define CHAR_UNSIGNED 0
|
||||
#else
|
||||
#define BYTES_REVERSED 0
|
||||
#define WORDS_REVERSED 0
|
||||
#define CHAR_UNSIGNED 0
|
||||
#endif
|
||||
112
commands/aal/format.c
Executable file
112
commands/aal/format.c
Executable file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
|
||||
extern char *long2str();
|
||||
|
||||
static int
|
||||
integral(c)
|
||||
{
|
||||
switch (c) {
|
||||
case 'b':
|
||||
return -2;
|
||||
case 'd':
|
||||
return 10;
|
||||
case 'o':
|
||||
return -8;
|
||||
case 'u':
|
||||
return -10;
|
||||
case 'x':
|
||||
return -16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*VARARGS2*/
|
||||
/*FORMAT1 $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
int
|
||||
_format(buf, fmt, argp)
|
||||
char *buf, *fmt;
|
||||
register va_list argp;
|
||||
{
|
||||
register char *pf = fmt;
|
||||
register char *pb = buf;
|
||||
|
||||
while (*pf) {
|
||||
if (*pf == '%') {
|
||||
register width, base, pad, npad;
|
||||
char *arg;
|
||||
char cbuf[2];
|
||||
char *badformat = "<bad format>";
|
||||
|
||||
/* get padder */
|
||||
if (*++pf == '0') {
|
||||
pad = '0';
|
||||
++pf;
|
||||
}
|
||||
else
|
||||
pad = ' ';
|
||||
|
||||
/* get width */
|
||||
width = 0;
|
||||
while (*pf >= '0' && *pf <= '9')
|
||||
width = 10 * width + *pf++ - '0';
|
||||
|
||||
if (*pf == 's') {
|
||||
arg = va_arg(argp, char *);
|
||||
}
|
||||
else
|
||||
if (*pf == 'c') {
|
||||
cbuf[0] = va_arg(argp, int);
|
||||
cbuf[1] = '\0';
|
||||
arg = &cbuf[0];
|
||||
}
|
||||
else
|
||||
if (*pf == 'l') {
|
||||
/* alignment ??? */
|
||||
if (base = integral(*++pf)) {
|
||||
arg = long2str(va_arg(argp,long), base);
|
||||
}
|
||||
else {
|
||||
pf--;
|
||||
arg = badformat;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (base = integral(*pf)) {
|
||||
arg = long2str((long)va_arg(argp,int), base);
|
||||
}
|
||||
else
|
||||
if (*pf == '%')
|
||||
arg = "%";
|
||||
else
|
||||
arg = badformat;
|
||||
|
||||
npad = width - strlen(arg);
|
||||
|
||||
while (npad-- > 0)
|
||||
*pb++ = pad;
|
||||
|
||||
while (*pb++ = *arg++);
|
||||
pb--;
|
||||
pf++;
|
||||
}
|
||||
else
|
||||
*pb++ = *pf++;
|
||||
}
|
||||
return pb - buf;
|
||||
}
|
||||
19
commands/aal/local.h
Executable file
19
commands/aal/local.h
Executable file
@@ -0,0 +1,19 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* collection of options, selected by including or excluding 'defines' */
|
||||
|
||||
/* Version number of the EM object code */
|
||||
# define VERSION 3 /* 16 bits number */
|
||||
|
||||
/* The default machine used by ack, acc, apc */
|
||||
# define ACKM "minix"
|
||||
|
||||
/* size of local machine, either 0 (for 16 bit address space), or 1 */
|
||||
# undef BIGMACHINE 1
|
||||
|
||||
/* operating system, SYS_5, V7, BSD4_1 or BSD4_2; Do NOT delete the comment
|
||||
in the next line! */
|
||||
# define V7 1 /* SYSTEM */
|
||||
67
commands/aal/long2str.c
Executable file
67
commands/aal/long2str.c
Executable file
@@ -0,0 +1,67 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* Integer to String translator
|
||||
-> base is a value from [-16,-2] V [2,16]
|
||||
-> base < 0: see 'val' as unsigned value
|
||||
-> no checks for buffer overflow and illegal parameters
|
||||
(1985, EHB)
|
||||
*/
|
||||
|
||||
#define MAXWIDTH 32
|
||||
|
||||
char *
|
||||
long2str(val, base)
|
||||
register long val;
|
||||
register base;
|
||||
{
|
||||
static char numbuf[MAXWIDTH];
|
||||
static char vec[] = "0123456789ABCDEF";
|
||||
register char *p = &numbuf[MAXWIDTH];
|
||||
int sign = (base > 0);
|
||||
|
||||
*--p = '\0'; /* null-terminate string */
|
||||
if (val) {
|
||||
if (base > 0) {
|
||||
if (val < 0L) {
|
||||
long v1 = -val;
|
||||
if (v1 == val)
|
||||
goto overflow;
|
||||
val = v1;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
}
|
||||
else
|
||||
if (base < 0) { /* unsigned */
|
||||
base = -base;
|
||||
if (val < 0L) { /* taken from Amoeba src */
|
||||
register mod, i;
|
||||
overflow:
|
||||
mod = 0;
|
||||
for (i = 0; i < 8 * sizeof val; i++) {
|
||||
mod <<= 1;
|
||||
if (val < 0)
|
||||
mod++;
|
||||
val <<= 1;
|
||||
if (mod >= base) {
|
||||
mod -= base;
|
||||
val++;
|
||||
}
|
||||
}
|
||||
*--p = vec[mod];
|
||||
}
|
||||
}
|
||||
do {
|
||||
*--p = vec[(int) (val % base)];
|
||||
val /= base;
|
||||
} while (val != 0L);
|
||||
if (sign)
|
||||
*--p = '-'; /* don't forget it !! */
|
||||
}
|
||||
else
|
||||
*--p = '0'; /* just a simple 0 */
|
||||
return p;
|
||||
}
|
||||
76
commands/aal/object.h
Executable file
76
commands/aal/object.h
Executable file
@@ -0,0 +1,76 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "byte_order.h"
|
||||
#include <local.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if CHAR_UNSIGNED
|
||||
#define Xchar(ch) (ch)
|
||||
#else
|
||||
#define Xchar(ch) ((ch) & 0377)
|
||||
#endif
|
||||
|
||||
#if ! defined(BYTES_REVERSED)
|
||||
#define BYTES_REVERSED 1
|
||||
#endif
|
||||
|
||||
#if ! defined(WORDS_REVERSED)
|
||||
#define WORDS_REVERSED 1
|
||||
#endif
|
||||
|
||||
#if BYTES_REVERSED
|
||||
#define uget2(c) (Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8))
|
||||
#define Xput2(i, c) (((c)[0] = (i)), ((c)[1] = (i) >> 8))
|
||||
#define put2(i, c) { register int j = (i); Xput2(j, c); }
|
||||
#else
|
||||
#define uget2(c) (* ((unsigned short *) (c)))
|
||||
#define Xput2(i, c) (* ((short *) (c)) = (i))
|
||||
#define put2(i, c) Xput2(i, c)
|
||||
#endif
|
||||
|
||||
#define get2(c) ((short) uget2(c))
|
||||
|
||||
#if WORDS_REVERSED || BYTES_REVERSED
|
||||
#define get4(c) (uget2(c) | ((long) uget2((c)+2) << 16))
|
||||
#define put4(l, c) { register long x=(l); \
|
||||
Xput2((int)x,c); \
|
||||
Xput2((int)(x>>16),(c)+2); \
|
||||
}
|
||||
#else
|
||||
#define get4(c) (* ((long *) (c)))
|
||||
#define put4(l, c) (* ((long *) (c)) = (l))
|
||||
#endif
|
||||
|
||||
#define SECTCNT 3 /* number of sections with own output buffer */
|
||||
#if BIGMACHINE
|
||||
#define WBUFSIZ (8*BUFSIZ)
|
||||
#else
|
||||
#define WBUFSIZ BUFSIZ
|
||||
#endif
|
||||
|
||||
struct fil {
|
||||
int cnt;
|
||||
char *pnow;
|
||||
char *pbegin;
|
||||
long currpos;
|
||||
int fd;
|
||||
char pbuf[WBUFSIZ];
|
||||
};
|
||||
|
||||
extern struct fil __parts[];
|
||||
|
||||
#define PARTEMIT 0
|
||||
#define PARTRELO (PARTEMIT+SECTCNT)
|
||||
#define PARTNAME (PARTRELO+1)
|
||||
#define PARTCHAR (PARTNAME+1)
|
||||
#ifdef SYMDBUG
|
||||
#define PARTDBUG (PARTCHAR+1)
|
||||
#else
|
||||
#define PARTDBUG (PARTCHAR+0)
|
||||
#endif
|
||||
#define NPARTS (PARTDBUG + 1)
|
||||
|
||||
#define getsect(s) (PARTEMIT+((s)>=(SECTCNT-1)?(SECTCNT-1):(s)))
|
||||
126
commands/aal/out.h
Executable file
126
commands/aal/out.h
Executable file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef __OUT_H_INCLUDED
|
||||
#define __OUT_H_INCLUDED
|
||||
/*
|
||||
* output format for ACK assemblers
|
||||
*/
|
||||
#ifndef ushort
|
||||
#define ushort unsigned short
|
||||
#endif /* ushort */
|
||||
|
||||
struct outhead {
|
||||
ushort oh_magic; /* magic number */
|
||||
ushort oh_stamp; /* version stamp */
|
||||
ushort oh_flags; /* several format flags */
|
||||
ushort oh_nsect; /* number of outsect structures */
|
||||
ushort oh_nrelo; /* number of outrelo structures */
|
||||
ushort oh_nname; /* number of outname structures */
|
||||
long oh_nemit; /* sum of all os_flen */
|
||||
long oh_nchar; /* size of string area */
|
||||
};
|
||||
|
||||
#define O_MAGIC 0x0201 /* magic number of output file */
|
||||
#define O_STAMP 0 /* version stamp */
|
||||
#define MAXSECT 64 /* Maximum number of sections */
|
||||
|
||||
#define HF_LINK 0x0004 /* unresolved references left */
|
||||
#define HF_8086 0x0008 /* os_base specially encoded */
|
||||
|
||||
struct outsect {
|
||||
long os_base; /* startaddress in machine */
|
||||
long os_size; /* section size in machine */
|
||||
long os_foff; /* startaddress in file */
|
||||
long os_flen; /* section size in file */
|
||||
long os_lign; /* section alignment */
|
||||
};
|
||||
|
||||
struct outrelo {
|
||||
char or_type; /* type of reference */
|
||||
char or_sect; /* referencing section */
|
||||
ushort or_nami; /* referenced symbol index */
|
||||
long or_addr; /* referencing address */
|
||||
};
|
||||
|
||||
struct outname {
|
||||
union {
|
||||
char *on_ptr; /* symbol name (in core) */
|
||||
long on_off; /* symbol name (in file) */
|
||||
} on_u;
|
||||
#define on_mptr on_u.on_ptr
|
||||
#define on_foff on_u.on_off
|
||||
ushort on_type; /* symbol type */
|
||||
ushort on_desc; /* debug info */
|
||||
long on_valu; /* symbol value */
|
||||
};
|
||||
|
||||
/*
|
||||
* relocation type bits
|
||||
*/
|
||||
#define RELSZ 0x07 /* relocation length */
|
||||
#define RELO1 1 /* 1 byte */
|
||||
#define RELO2 2 /* 2 bytes */
|
||||
#define RELO4 4 /* 4 bytes */
|
||||
#define RELPC 0x08 /* pc relative */
|
||||
#define RELBR 0x10 /* High order byte lowest address. */
|
||||
#define RELWR 0x20 /* High order word lowest address. */
|
||||
|
||||
/*
|
||||
* section type bits and fields
|
||||
*/
|
||||
#define S_TYP 0x007F /* undefined, absolute or relative */
|
||||
#define S_EXT 0x0080 /* external flag */
|
||||
#define S_ETC 0x7F00 /* for symbolic debug, bypassing 'as' */
|
||||
|
||||
/*
|
||||
* S_TYP field values
|
||||
*/
|
||||
#define S_UND 0x0000 /* undefined item */
|
||||
#define S_ABS 0x0001 /* absolute item */
|
||||
#define S_MIN 0x0002 /* first user section */
|
||||
#define S_MAX (S_TYP-1) /* last user section */
|
||||
#define S_CRS S_TYP /* on_valu is symbol index which contains value */
|
||||
|
||||
/*
|
||||
* S_ETC field values
|
||||
*/
|
||||
#define S_SCT 0x0100 /* section names */
|
||||
#define S_LIN 0x0200 /* hll source line item */
|
||||
#define S_FIL 0x0300 /* hll source file item */
|
||||
#define S_MOD 0x0400 /* ass source file item */
|
||||
#define S_COM 0x1000 /* Common name. */
|
||||
#define S_STB 0xe000 /* entries with any of these bits set are
|
||||
reserved for debuggers
|
||||
*/
|
||||
|
||||
/*
|
||||
* structure format strings
|
||||
*/
|
||||
#define SF_HEAD "22222244"
|
||||
#define SF_SECT "44444"
|
||||
#define SF_RELO "1124"
|
||||
#define SF_NAME "4224"
|
||||
|
||||
/*
|
||||
* structure sizes (bytes in file; add digits in SF_*)
|
||||
*/
|
||||
#define SZ_HEAD 20
|
||||
#define SZ_SECT 20
|
||||
#define SZ_RELO 8
|
||||
#define SZ_NAME 12
|
||||
|
||||
/*
|
||||
* file access macros
|
||||
*/
|
||||
#define BADMAGIC(x) ((x).oh_magic!=O_MAGIC)
|
||||
#define OFF_SECT(x) SZ_HEAD
|
||||
#define OFF_EMIT(x) (OFF_SECT(x) + ((long)(x).oh_nsect * SZ_SECT))
|
||||
#define OFF_RELO(x) (OFF_EMIT(x) + (x).oh_nemit)
|
||||
#define OFF_NAME(x) (OFF_RELO(x) + ((long)(x).oh_nrelo * SZ_RELO))
|
||||
#define OFF_CHAR(x) (OFF_NAME(x) + ((long)(x).oh_nname * SZ_NAME))
|
||||
|
||||
#endif /* __OUT_H_INCLUDED */
|
||||
7
commands/aal/param.h
Executable file
7
commands/aal/param.h
Executable file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#define SSIZE 1024
|
||||
42
commands/aal/print.c
Executable file
42
commands/aal/print.c
Executable file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <system.h>
|
||||
#include "param.h"
|
||||
|
||||
/*VARARGS*/
|
||||
/*FORMAT0v $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
int
|
||||
#if __STDC__
|
||||
print(char *fmt, ...)
|
||||
#else
|
||||
print(fmt, va_alist)
|
||||
char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char buf[SSIZE];
|
||||
|
||||
#if __STDC__
|
||||
va_start(args, fmt);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
sys_write(STDOUT, buf, _format(buf, fmt, args));
|
||||
va_end(args);
|
||||
}
|
||||
34
commands/aal/ranlib.h
Executable file
34
commands/aal/ranlib.h
Executable file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef __RANLIB_H_INCLUDED
|
||||
#define __RANLIB_H_INCLUDED
|
||||
|
||||
#ifndef SYMDEF
|
||||
# define SYMDEF "__.SYMDEF"
|
||||
#endif /* SYMDEF */
|
||||
|
||||
/*
|
||||
* Structure of the SYMDEF table of contents for an archive.
|
||||
* SYMDEF begins with a long giving the number of ranlib
|
||||
* structures that immediately follow, and then continues with a string
|
||||
* table consisting of a long giving the number of bytes of
|
||||
* strings that follow and then the strings themselves.
|
||||
*/
|
||||
struct ranlib {
|
||||
union {
|
||||
char *ran__ptr; /* symbol name (in core) */
|
||||
long ran__off; /* symbol name (in file) */
|
||||
} ran_u;
|
||||
#define ran_ptr ran_u.ran__ptr
|
||||
#define ran_off ran_u.ran__off
|
||||
long ran_pos; /* library member is at this position */
|
||||
};
|
||||
|
||||
#define SZ_RAN 8
|
||||
#define SF_RAN "44"
|
||||
|
||||
#endif /* __RANLIB_H_INCLUDED */
|
||||
254
commands/aal/rd.c
Executable file
254
commands/aal/rd.c
Executable file
@@ -0,0 +1,254 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <out.h>
|
||||
#include "object.h"
|
||||
|
||||
extern long lseek();
|
||||
|
||||
/*
|
||||
* Parts of the output file.
|
||||
*/
|
||||
#undef PARTEMIT
|
||||
#undef PARTRELO
|
||||
#undef PARTNAME
|
||||
#undef PARTCHAR
|
||||
#undef PARTDBUG
|
||||
#undef NPARTS
|
||||
|
||||
#define PARTEMIT 0
|
||||
#define PARTRELO 1
|
||||
#define PARTNAME 2
|
||||
#define PARTCHAR 3
|
||||
#ifdef SYMDBUG
|
||||
#define PARTDBUG 4
|
||||
#else
|
||||
#define PARTDBUG 3
|
||||
#endif
|
||||
#define NPARTS (PARTDBUG + 1)
|
||||
|
||||
static long offset[MAXSECT];
|
||||
|
||||
static int outfile;
|
||||
static long outseek[NPARTS];
|
||||
static long currpos;
|
||||
static long rd_base;
|
||||
#define OUTSECT(i) \
|
||||
(outseek[PARTEMIT] = offset[i])
|
||||
#define BEGINSEEK(p, o) \
|
||||
(outseek[(p)] = (o))
|
||||
|
||||
static int sectionnr;
|
||||
|
||||
static
|
||||
OUTREAD(p, b, n)
|
||||
char *b;
|
||||
long n;
|
||||
{
|
||||
register long l = outseek[p];
|
||||
|
||||
if (currpos != l) {
|
||||
lseek(outfile, l, 0);
|
||||
}
|
||||
rd_bytes(outfile, b, n);
|
||||
l += n;
|
||||
currpos = l;
|
||||
outseek[p] = l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the output file according to the chosen strategy.
|
||||
*/
|
||||
int
|
||||
rd_open(f)
|
||||
char *f;
|
||||
{
|
||||
|
||||
if ((outfile = open(f, 0)) < 0)
|
||||
return 0;
|
||||
return rd_fdopen(outfile);
|
||||
}
|
||||
|
||||
static int offcnt;
|
||||
|
||||
rd_fdopen(fd)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < NPARTS; i++) outseek[i] = 0;
|
||||
offcnt = 0;
|
||||
rd_base = lseek(fd, 0L, 1);
|
||||
if (rd_base < 0) {
|
||||
return 0;
|
||||
}
|
||||
currpos = rd_base;
|
||||
outseek[PARTEMIT] = currpos;
|
||||
outfile = fd;
|
||||
sectionnr = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
rd_close()
|
||||
{
|
||||
|
||||
close(outfile);
|
||||
outfile = -1;
|
||||
}
|
||||
|
||||
rd_fd()
|
||||
{
|
||||
return outfile;
|
||||
}
|
||||
|
||||
rd_ohead(head)
|
||||
register struct outhead *head;
|
||||
{
|
||||
register long off;
|
||||
|
||||
OUTREAD(PARTEMIT, (char *) head, (long) SZ_HEAD);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outhead) != SZ_HEAD)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) head + (SZ_HEAD-4);
|
||||
|
||||
head->oh_nchar = get4(c);
|
||||
c -= 4; head->oh_nemit = get4(c);
|
||||
c -= 2; head->oh_nname = uget2(c);
|
||||
c -= 2; head->oh_nrelo = uget2(c);
|
||||
c -= 2; head->oh_nsect = uget2(c);
|
||||
c -= 2; head->oh_flags = uget2(c);
|
||||
c -= 2; head->oh_stamp = uget2(c);
|
||||
c -= 2; head->oh_magic = uget2(c);
|
||||
}
|
||||
off = OFF_RELO(*head) + rd_base;
|
||||
BEGINSEEK(PARTRELO, off);
|
||||
off += (long) head->oh_nrelo * SZ_RELO;
|
||||
BEGINSEEK(PARTNAME, off);
|
||||
off += (long) head->oh_nname * SZ_NAME;
|
||||
BEGINSEEK(PARTCHAR, off);
|
||||
#ifdef SYMDBUG
|
||||
off += head->oh_nchar;
|
||||
BEGINSEEK(PARTDBUG, off);
|
||||
#endif
|
||||
}
|
||||
|
||||
rd_rew_relos(head)
|
||||
register struct outhead *head;
|
||||
{
|
||||
register long off = OFF_RELO(*head) + rd_base;
|
||||
|
||||
BEGINSEEK(PARTRELO, off);
|
||||
}
|
||||
|
||||
rd_sect(sect, cnt)
|
||||
register struct outsect *sect;
|
||||
register unsigned int cnt;
|
||||
{
|
||||
register char *c = (char *) sect + cnt * SZ_SECT;
|
||||
|
||||
OUTREAD(PARTEMIT, (char *) sect, (long)cnt * SZ_SECT);
|
||||
sect += cnt;
|
||||
offcnt += cnt;
|
||||
while (cnt--) {
|
||||
sect--;
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outsect) != SZ_SECT)
|
||||
#endif
|
||||
{
|
||||
c -= 4; sect->os_lign = get4(c);
|
||||
c -= 4; sect->os_flen = get4(c);
|
||||
c -= 4; sect->os_foff = get4(c);
|
||||
}
|
||||
offset[--offcnt] = sect->os_foff + rd_base;
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outsect) != SZ_SECT)
|
||||
#endif
|
||||
{
|
||||
c -= 4; sect->os_size = get4(c);
|
||||
c -= 4; sect->os_base = get4(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rd_outsect(s)
|
||||
{
|
||||
OUTSECT(s);
|
||||
sectionnr = s;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't have to worry about byte order here.
|
||||
*/
|
||||
rd_emit(emit, cnt)
|
||||
char *emit;
|
||||
long cnt;
|
||||
{
|
||||
OUTREAD(PARTEMIT, emit, cnt);
|
||||
offset[sectionnr] += cnt;
|
||||
}
|
||||
|
||||
rd_relo(relo, cnt)
|
||||
register struct outrelo *relo;
|
||||
register unsigned int cnt;
|
||||
{
|
||||
|
||||
OUTREAD(PARTRELO, (char *) relo, (long) cnt * SZ_RELO);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outrelo) != SZ_RELO)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) relo + (long) cnt * SZ_RELO;
|
||||
|
||||
relo += cnt;
|
||||
while (cnt--) {
|
||||
relo--;
|
||||
c -= 4; relo->or_addr = get4(c);
|
||||
c -= 2; relo->or_nami = uget2(c);
|
||||
relo->or_sect = *--c;
|
||||
relo->or_type = *--c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rd_name(name, cnt)
|
||||
register struct outname *name;
|
||||
register unsigned int cnt;
|
||||
{
|
||||
|
||||
OUTREAD(PARTNAME, (char *) name, (long) cnt * SZ_NAME);
|
||||
#if ! (BYTES_REVERSED || WORDS_REVERSED)
|
||||
if (sizeof(struct outname) != SZ_NAME)
|
||||
#endif
|
||||
{
|
||||
register char *c = (char *) name + (long) cnt * SZ_NAME;
|
||||
|
||||
name += cnt;
|
||||
while (cnt--) {
|
||||
name--;
|
||||
c -= 4; name->on_valu = get4(c);
|
||||
c -= 2; name->on_desc = uget2(c);
|
||||
c -= 2; name->on_type = uget2(c);
|
||||
c -= 4; name->on_foff = get4(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rd_string(addr, len)
|
||||
char *addr;
|
||||
long len;
|
||||
{
|
||||
|
||||
OUTREAD(PARTCHAR, addr, len);
|
||||
}
|
||||
|
||||
#ifdef SYMDBUG
|
||||
rd_dbug(buf, size)
|
||||
char *buf;
|
||||
long size;
|
||||
{
|
||||
OUTREAD(PARTDBUG, buf, size);
|
||||
}
|
||||
#endif
|
||||
35
commands/aal/rd_arhdr.c
Executable file
35
commands/aal/rd_arhdr.c
Executable file
@@ -0,0 +1,35 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include "object.h"
|
||||
|
||||
int
|
||||
rd_arhdr(fd, arhdr)
|
||||
register struct ar_hdr *arhdr;
|
||||
{
|
||||
char buf[AR_TOTAL];
|
||||
register char *c = buf;
|
||||
register char *p = arhdr->ar_name;
|
||||
register int i;
|
||||
|
||||
i = read(fd, c, AR_TOTAL);
|
||||
if (i == 0) return 0;
|
||||
if (i != AR_TOTAL) {
|
||||
rd_fatal();
|
||||
}
|
||||
i = 14;
|
||||
while (i--) {
|
||||
*p++ = *c++;
|
||||
}
|
||||
arhdr->ar_date = ((long) get2(c)) << 16; c += 2;
|
||||
arhdr->ar_date |= ((long) get2(c)) & 0xffff; c += 2;
|
||||
arhdr->ar_uid = *c++;
|
||||
arhdr->ar_gid = *c++;
|
||||
arhdr->ar_mode = get2(c); c += 2;
|
||||
arhdr->ar_size = (long) get2(c) << 16; c += 2;
|
||||
arhdr->ar_size |= (long) get2(c) & 0xffff;
|
||||
return 1;
|
||||
}
|
||||
32
commands/aal/rd_bytes.c
Executable file
32
commands/aal/rd_bytes.c
Executable file
@@ -0,0 +1,32 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#define MININT (1 << (sizeof(int) * 8 - 1))
|
||||
#define MAXCHUNK (~MININT) /* Highest count we read(2). */
|
||||
/* Unfortunately, MAXCHUNK is too large with some compilers. Put it in
|
||||
an int!
|
||||
*/
|
||||
|
||||
static int maxchunk = MAXCHUNK;
|
||||
|
||||
/*
|
||||
* We don't have to worry about byte order here.
|
||||
* Just read "cnt" bytes from file-descriptor "fd".
|
||||
*/
|
||||
int
|
||||
rd_bytes(fd, string, cnt)
|
||||
register char *string;
|
||||
register long cnt;
|
||||
{
|
||||
|
||||
while (cnt) {
|
||||
register int n = cnt >= maxchunk ? maxchunk : cnt;
|
||||
|
||||
if (read(fd, string, n) != n)
|
||||
rd_fatal();
|
||||
string += n;
|
||||
cnt -= n;
|
||||
}
|
||||
}
|
||||
15
commands/aal/rd_unsig2.c
Executable file
15
commands/aal/rd_unsig2.c
Executable file
@@ -0,0 +1,15 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
|
||||
unsigned int
|
||||
rd_unsigned2(fd)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
rd_bytes(fd, buf, 2L);
|
||||
return uget2(buf);
|
||||
}
|
||||
42
commands/aal/sprint.c
Executable file
42
commands/aal/sprint.c
Executable file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#if __STDC__
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#endif
|
||||
#include <system.h>
|
||||
#include "param.h"
|
||||
|
||||
/*VARARGS*/
|
||||
/*FORMAT1v $
|
||||
%s = char *
|
||||
%l = long
|
||||
%c = int
|
||||
%[uxbo] = unsigned int
|
||||
%d = int
|
||||
$ */
|
||||
char *
|
||||
#if __STDC__
|
||||
sprint(char *buf, char *fmt, ...)
|
||||
#else
|
||||
sprint(buf, fmt, va_alist)
|
||||
char *buf, *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
|
||||
#if __STDC__
|
||||
va_start(args, fmt);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
buf[_format(buf, fmt, args)] = '\0';
|
||||
va_end(args);
|
||||
return buf;
|
||||
}
|
||||
24
commands/aal/system.c
Executable file
24
commands/aal/system.c
Executable file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* RCS: $Header$ */
|
||||
|
||||
#include <system.h>
|
||||
|
||||
File _sys_ftab[SYS_NOPEN] = {
|
||||
{ 0, OP_READ},
|
||||
{ 1, OP_APPEND},
|
||||
{ 2, OP_APPEND}
|
||||
};
|
||||
|
||||
File *
|
||||
_get_entry()
|
||||
{
|
||||
register File *fp;
|
||||
|
||||
for (fp = &_sys_ftab[0]; fp < &_sys_ftab[SYS_NOPEN]; fp++)
|
||||
if (fp->o_flags == 0)
|
||||
return fp;
|
||||
return (File *)0;
|
||||
}
|
||||
47
commands/aal/system.h
Executable file
47
commands/aal/system.h
Executable file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* RCS: $Header$ */
|
||||
#ifndef __SYSTEM_INCLUDED__
|
||||
#define __SYSTEM_INCLUDED__
|
||||
|
||||
struct _sys_fildes {
|
||||
int o_fd; /* UNIX filedescriptor */
|
||||
int o_flags; /* flags for open; 0 if not used */
|
||||
};
|
||||
|
||||
typedef struct _sys_fildes File;
|
||||
|
||||
extern File _sys_ftab[];
|
||||
|
||||
/* flags for sys_open() */
|
||||
#define OP_READ 01
|
||||
#define OP_WRITE 02
|
||||
#define OP_APPEND 04
|
||||
|
||||
/* flags for sys_access() */
|
||||
#define AC_EXIST 00
|
||||
#define AC_READ 04
|
||||
#define AC_WRITE 02
|
||||
#define AC_EXEC 01
|
||||
|
||||
/* flags for sys_stop() */
|
||||
#define S_END 0
|
||||
#define S_EXIT 1
|
||||
#define S_ABORT 2
|
||||
|
||||
/* standard file decsriptors */
|
||||
#define STDIN &_sys_ftab[0]
|
||||
#define STDOUT &_sys_ftab[1]
|
||||
#define STDERR &_sys_ftab[2]
|
||||
|
||||
/* maximum number of open files */
|
||||
#define SYS_NOPEN 20
|
||||
|
||||
/* return value for sys_break */
|
||||
#define ILL_BREAK ((char *)0)
|
||||
|
||||
/* system's idea of block */
|
||||
#define BUFSIZ 1024
|
||||
#endif __SYSTEM_INCLUDED__
|
||||
16
commands/aal/varargs.h
Executable file
16
commands/aal/varargs.h
Executable file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/* $Header$ */
|
||||
|
||||
#ifndef _VARARGS_H
|
||||
#define _VARARGS_H
|
||||
|
||||
typedef char *va_list;
|
||||
# define __va_sz(mode) (((sizeof(mode) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
|
||||
# define va_dcl int va_alist;
|
||||
# define va_start(list) (list = (char *) &va_alist)
|
||||
# define va_end(list)
|
||||
# define va_arg(list,mode) (*((mode *)((list += __va_sz(mode)) - __va_sz(mode))))
|
||||
#endif /* _VARARGS_H */
|
||||
28
commands/aal/wr_arhdr.c
Executable file
28
commands/aal/wr_arhdr.c
Executable file
@@ -0,0 +1,28 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include <arch.h>
|
||||
#include "object.h"
|
||||
|
||||
wr_arhdr(fd, arhdr)
|
||||
register struct ar_hdr *arhdr;
|
||||
{
|
||||
char buf[AR_TOTAL];
|
||||
register char *c = buf;
|
||||
register char *p = arhdr->ar_name;
|
||||
register int i = 14;
|
||||
|
||||
while (i--) {
|
||||
*c++ = *p++;
|
||||
}
|
||||
put2((int)(arhdr->ar_date>>16),c); c += 2;
|
||||
put2((int)(arhdr->ar_date),c); c += 2;
|
||||
*c++ = arhdr->ar_uid;
|
||||
*c++ = arhdr->ar_gid;
|
||||
put2(arhdr->ar_mode,c); c += 2;
|
||||
put2((int)(arhdr->ar_size>>16),c); c += 2;
|
||||
put2((int)(arhdr->ar_size),c);
|
||||
wr_bytes(fd, buf, (long) AR_TOTAL);
|
||||
}
|
||||
30
commands/aal/wr_bytes.c
Executable file
30
commands/aal/wr_bytes.c
Executable file
@@ -0,0 +1,30 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#define MININT (1 << (sizeof(int) * 8 - 1))
|
||||
#define MAXCHUNK (~MININT) /* Highest count we write(2). */
|
||||
/* Notice that MAXCHUNK itself might be too large with some compilers.
|
||||
You have to put it in an int!
|
||||
*/
|
||||
|
||||
static int maxchunk = MAXCHUNK;
|
||||
|
||||
/*
|
||||
* Just write "cnt" bytes to file-descriptor "fd".
|
||||
*/
|
||||
wr_bytes(fd, string, cnt)
|
||||
register char *string;
|
||||
register long cnt;
|
||||
{
|
||||
|
||||
while (cnt) {
|
||||
register int n = cnt >= maxchunk ? maxchunk : cnt;
|
||||
|
||||
if (write(fd, string, n) != n)
|
||||
wr_fatal();
|
||||
string += n;
|
||||
cnt -= n;
|
||||
}
|
||||
}
|
||||
14
commands/aal/wr_int2.c
Executable file
14
commands/aal/wr_int2.c
Executable file
@@ -0,0 +1,14 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
|
||||
wr_int2(fd, i)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
put2(i, buf);
|
||||
wr_bytes(fd, buf, 2L);
|
||||
}
|
||||
15
commands/aal/wr_long.c
Executable file
15
commands/aal/wr_long.c
Executable file
@@ -0,0 +1,15 @@
|
||||
/* $Header$ */
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
#include "object.h"
|
||||
|
||||
wr_long(fd, l)
|
||||
long l;
|
||||
{
|
||||
char buf[4];
|
||||
|
||||
put4(l, buf);
|
||||
wr_bytes(fd, buf, 4L);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user