new-build: get rid of Go(ogle) with few rc scripts
Also, in binutils: fix inlining compilation error, see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242053
This commit is contained in:
parent
6b473cd28f
commit
0c2dabf975
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,6 +1,3 @@
|
|||||||
third_party/pkg/
|
|
||||||
third_party/src/github.com/kr/
|
|
||||||
third_party/src/github.com/creack/
|
|
||||||
third_party/src/golang.org/
|
|
||||||
|
|
||||||
*.build.log
|
*.build.log
|
||||||
|
|
||||||
|
lib/
|
||||||
|
19
.gitmodules
vendored
19
.gitmodules
vendored
@ -1,13 +1,18 @@
|
|||||||
[submodule "third_party/src/github.com/lionkov/ninep"]
|
|
||||||
path = third_party/src/github.com/lionkov/ninep
|
|
||||||
url = https://github.com/JehanneOS/devtools-ninep.git
|
|
||||||
branch = master
|
|
||||||
[submodule "third_party/src/github.com/0intro/drawterm"]
|
|
||||||
path = third_party/src/github.com/0intro/drawterm
|
|
||||||
url = https://github.com/JehanneOS/devtools-drawterm.git
|
|
||||||
[submodule "cross/pkgs/newlib/src"]
|
[submodule "cross/pkgs/newlib/src"]
|
||||||
path = cross/pkgs/newlib/src
|
path = cross/pkgs/newlib/src
|
||||||
url = https://github.com/JehanneOS/newlib.git
|
url = https://github.com/JehanneOS/newlib.git
|
||||||
[submodule "cross/pkgs/mksh"]
|
[submodule "cross/pkgs/mksh"]
|
||||||
path = cross/pkgs/mksh/src
|
path = cross/pkgs/mksh/src
|
||||||
url = https://github.com/JehanneOS/mksh.git
|
url = https://github.com/JehanneOS/mksh.git
|
||||||
|
[submodule "src/trampoline"]
|
||||||
|
path = src/trampoline
|
||||||
|
url = https://tesio@bitbucket.org/tesio/trampoline.git
|
||||||
|
[submodule "src/u9fs"]
|
||||||
|
path = src/u9fs
|
||||||
|
url = https://bitbucket.org/plan9-from-bell-labs/u9fs.git
|
||||||
|
[submodule "src/drawterm"]
|
||||||
|
path = src/drawterm
|
||||||
|
url = https://github.com/JehanneOS/devtools-drawterm.git
|
||||||
|
[submodule "src/netcat"]
|
||||||
|
path = src/netcat
|
||||||
|
url = https://git.code.sf.net/p/nc110/git
|
||||||
|
4
QA.sh
4
QA.sh
@ -11,7 +11,7 @@ fi
|
|||||||
|
|
||||||
trap : 2
|
trap : 2
|
||||||
|
|
||||||
$JEHANNE/hacking/bin/ufs -d=0 -root=$JEHANNE &
|
$JEHANNE/hacking/bin/nc -p 5640 -l -e $JEHANNE/hacking/bin/start-u9fs.sh &
|
||||||
ufspid=$!
|
ufspid=$!
|
||||||
|
|
||||||
export machineflag=pc
|
export machineflag=pc
|
||||||
@ -76,6 +76,6 @@ EOF
|
|||||||
echo $cmd
|
echo $cmd
|
||||||
eval $cmd
|
eval $cmd
|
||||||
|
|
||||||
kill $ufspid
|
# kill $ufspid # not needed anymore thank to netcat
|
||||||
wait
|
wait
|
||||||
|
|
||||||
|
1
bin/.gitignore
vendored
1
bin/.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*
|
*
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!build
|
||||||
|
57
bin/runqemu
Executable file
57
bin/runqemu
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env rc
|
||||||
|
# poor man portable expect
|
||||||
|
|
||||||
|
QPROMPT='10.0.2.15# '
|
||||||
|
INFILE=/tmp/runqemu.$pid.in
|
||||||
|
OUTFILE=/tmp/runqemu.$pid.out
|
||||||
|
|
||||||
|
cd $JEHANNE/arch/amd64/kern
|
||||||
|
echo -n > $INFILE
|
||||||
|
echo -n > $OUTFILE
|
||||||
|
|
||||||
|
@{tail -f $INFILE | $JEHANNE/hacking/QA.sh >> $OUTFILE} &
|
||||||
|
QPID=$apid
|
||||||
|
|
||||||
|
tail -f $OUTFILE &
|
||||||
|
TPID=$apid
|
||||||
|
|
||||||
|
ifs='
|
||||||
|
'
|
||||||
|
INPUT=`{cat}
|
||||||
|
|
||||||
|
fn descendants {
|
||||||
|
if( ! ~ 0 $#1 ) {
|
||||||
|
echo $1;
|
||||||
|
ps -o pid= --ppid $1|xargs -n 1 rc -c 'descendants $1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quit {
|
||||||
|
kill -2 `{descendants $QPID}
|
||||||
|
kill -2 $TPID
|
||||||
|
wait
|
||||||
|
rm $INFILE
|
||||||
|
rm $OUTFILE
|
||||||
|
exit $1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn failOnError {
|
||||||
|
if( ! ~ 0 `{cat $OUTFILE | grep FAIL | wc -c}){
|
||||||
|
quit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(cmd in $INPUT){
|
||||||
|
while( ~ 0 `{tail -n 1 $OUTFILE | sed -n '/'$QPROMPT'/p' | wc -c}){
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
failOnError
|
||||||
|
echo $cmd >> $INFILE
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
|
||||||
|
while( ~ 0 `{tail -n 1 $OUTFILE | sed -n '/'$QPROMPT'/p' | wc -c}){
|
||||||
|
sleep 2
|
||||||
|
}
|
||||||
|
failOnError
|
||||||
|
quit
|
3
bin/start-u9fs.sh
Executable file
3
bin/start-u9fs.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# U9FS_LOG="-l $JEHANNE/hacking/lib/u9fs.log -z -D"
|
||||||
|
$JEHANNE/hacking/bin/u9fs $U9FS_LOG -a none -u $USER $JEHANNE
|
3
bin/template
Executable file
3
bin/template
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
$JEHANNE/hacking/bin/rc $JEHANNE/arch/rc/cmd/template $@
|
@ -4,16 +4,16 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2016-2017 Giacomo Tesio <giacomo@tesio.it>
|
# Copyright (C) 2016-2017 Giacomo Tesio <giacomo@tesio.it>
|
||||||
|
|
||||||
BUILD_GO_TOOLS=true
|
BUILD_TRAMPOLINE=true
|
||||||
BUILD_DRAWTERM=true
|
BUILD_DRAWTERM=true
|
||||||
|
|
||||||
while test $# -gt 0
|
while test $# -gt 0
|
||||||
do
|
do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--help) echo "$0 [ --no-tools | --no-drawterm | --help ]"
|
--help) echo "$0 [ --no-trampoline | --no-drawterm | --help ]"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
--no-tools) BUILD_GO_TOOLS=false
|
--no-tools) BUILD_TRAMPOLINE=false
|
||||||
;;
|
;;
|
||||||
--no-drawterm) BUILD_DRAWTERM=false
|
--no-drawterm) BUILD_DRAWTERM=false
|
||||||
;;
|
;;
|
||||||
@ -29,10 +29,10 @@ cd `dirname $0`
|
|||||||
if [ -z "$UTILITIES" ]; then
|
if [ -z "$UTILITIES" ]; then
|
||||||
UTILITIES=`pwd`
|
UTILITIES=`pwd`
|
||||||
fi
|
fi
|
||||||
if [ "$BUILD_GO_TOOLS$BUILD_DRAWTERM" = "truetrue" ]; then
|
if [ "$BUILD_TRAMPOLINE$BUILD_DRAWTERM" = "truetrue" ]; then
|
||||||
git clean -x -d -f $UTILITIES/bin
|
git clean -x -d -f $UTILITIES/bin
|
||||||
fi
|
fi
|
||||||
if [ "$BUILD_GO_TOOLS" = "true" ]; then
|
if [ "$BUILD_TRAMPOLINE" = "true" ]; then
|
||||||
echo -n Building development tools.
|
echo -n Building development tools.
|
||||||
(
|
(
|
||||||
# Inside parentheses, and therefore a subshell . . .
|
# Inside parentheses, and therefore a subshell . . .
|
||||||
@ -44,18 +44,20 @@ if [ "$BUILD_GO_TOOLS" = "true" ]; then
|
|||||||
) &
|
) &
|
||||||
dotter=$!
|
dotter=$!
|
||||||
(
|
(
|
||||||
GOBIN="$UTILITIES/bin" GOPATH="$UTILITIES/third_party:$UTILITIES" go get -d jehanne/cmd/... &&
|
(cd $UTILITIES/src/trampoline/ && ./build.sh)
|
||||||
GOBIN="$UTILITIES/bin" GOPATH="$UTILITIES/third_party:$UTILITIES" go install jehanne/cmd/... &&
|
(cd $UTILITIES/src/netcat && XLIB=-lresolv DFLAGS=-DGAPING_SECURITY_HOLE make linux && mv nc $UTILITIES/bin && git clean -xdf .)
|
||||||
GOBIN="$UTILITIES/bin" GOPATH="$UTILITIES/third_party:$UTILITIES" go install github.com/lionkov/ninep/srv/examples/ufs
|
(cd $UTILITIES/src/u9fs && make && mv u9fs $UTILITIES/bin && git clean -xdf .)
|
||||||
)
|
) > $UTILITIES/src/utils.build.log 2>&1
|
||||||
STATUS="$?"
|
STATUS="$?"
|
||||||
kill $dotter
|
kill $dotter
|
||||||
wait $dotter 2>/dev/null
|
wait $dotter 2>/dev/null
|
||||||
if [ ! $STATUS -eq "0" ]
|
if [ ! $STATUS -eq "0" ]
|
||||||
then
|
then
|
||||||
echo "FAIL"
|
echo "FAIL"
|
||||||
|
cat utils.build.log
|
||||||
exit $STATUS
|
exit $STATUS
|
||||||
else
|
else
|
||||||
|
rm $UTILITIES/src/utils.build.log
|
||||||
echo "done."
|
echo "done."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -72,7 +74,7 @@ if [ "$BUILD_DRAWTERM" = "true" ]; then
|
|||||||
) &
|
) &
|
||||||
dotter=$!
|
dotter=$!
|
||||||
(
|
(
|
||||||
cd $UTILITIES/third_party/src/github.com/0intro/drawterm/ &&
|
cd $UTILITIES/src/drawterm/ &&
|
||||||
git clean -xdf > ../drawterm.build.log 2>&1 &&
|
git clean -xdf > ../drawterm.build.log 2>&1 &&
|
||||||
CONF=unix make >> ../drawterm.build.log 2>&1 &&
|
CONF=unix make >> ../drawterm.build.log 2>&1 &&
|
||||||
mv drawterm $UTILITIES/bin
|
mv drawterm $UTILITIES/bin
|
||||||
@ -82,11 +84,11 @@ if [ "$BUILD_DRAWTERM" = "true" ]; then
|
|||||||
wait $dotter 2>/dev/null
|
wait $dotter 2>/dev/null
|
||||||
if [ $STATUS -eq "0" ]
|
if [ $STATUS -eq "0" ]
|
||||||
then
|
then
|
||||||
rm $UTILITIES/third_party/src/github.com/0intro/drawterm.build.log
|
rm $UTILITIES/src/drawterm.build.log
|
||||||
echo "done."
|
echo "done."
|
||||||
else
|
else
|
||||||
echo "FAIL"
|
echo "FAIL"
|
||||||
cat $UTILITIES/third_party/src/github.com/0intro/drawterm.build.log
|
cat $$UTILITIES/src/drawterm.build.log
|
||||||
exit $STATUS
|
exit $STATUS
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -54,16 +54,7 @@ if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then
|
|||||||
export TOOLPREFIX=x86_64-jehanne-
|
export TOOLPREFIX=x86_64-jehanne-
|
||||||
export CC=x86_64-jehanne-gcc
|
export CC=x86_64-jehanne-gcc
|
||||||
|
|
||||||
echo
|
build
|
||||||
echo "Vendorized code verification..."
|
|
||||||
echo
|
|
||||||
for v in `find $JEHANNE -type f|grep vendor.json`; do
|
|
||||||
echo "cd `dirname $v`"
|
|
||||||
(cd `dirname $v`; vendor -check)
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
build all
|
|
||||||
|
|
||||||
if [ "$TRAVIS_BUILD_DIR" != "" ]; then
|
if [ "$TRAVIS_BUILD_DIR" != "" ]; then
|
||||||
if [ "$QA_CHECKS" != "" ]; then
|
if [ "$QA_CHECKS" != "" ]; then
|
||||||
|
@ -51,7 +51,7 @@ function dynpatch {
|
|||||||
|
|
||||||
|
|
||||||
# setup Jehanne's headers
|
# setup Jehanne's headers
|
||||||
usyscalls header $JEHANNE/sys/src/sysconf.json > $JEHANNE/arch/amd64/include/syscalls.h
|
cat $JEHANNE/sys/src/lib/jehanne/syscallh.rc.template | template | rc | sed 's/ ,/,/g; s/ )/)/g' > $JEHANNE/arch/amd64/include/syscalls.h
|
||||||
|
|
||||||
mkdir -p $WORKING_DIR
|
mkdir -p $WORKING_DIR
|
||||||
date > $LOG
|
date > $LOG
|
||||||
@ -63,7 +63,7 @@ failOnError $? "libtool installation check"
|
|||||||
|
|
||||||
cp -fpr $JEHANNE/hacking/cross/src $WORKING_DIR
|
cp -fpr $JEHANNE/hacking/cross/src $WORKING_DIR
|
||||||
cd $WORKING_DIR/src
|
cd $WORKING_DIR/src
|
||||||
fetch >> $LOG
|
./fetch.sh >> $LOG
|
||||||
failOnError $? "fetching sources"
|
failOnError $? "fetching sources"
|
||||||
|
|
||||||
mkdir -p $WORKING_DIR/build
|
mkdir -p $WORKING_DIR/build
|
||||||
@ -76,10 +76,12 @@ echo -n Building binutils...
|
|||||||
export BINUTILS_BUILD_DIR=$WORKING_DIR/build/binutils
|
export BINUTILS_BUILD_DIR=$WORKING_DIR/build/binutils
|
||||||
mkdir -p $BINUTILS_BUILD_DIR
|
mkdir -p $BINUTILS_BUILD_DIR
|
||||||
|
|
||||||
|
# for libctf/swap.h patch see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242053
|
||||||
( ( grep -q jehanne $WORKING_DIR/src/binutils/config.sub || (
|
( ( grep -q jehanne $WORKING_DIR/src/binutils/config.sub || (
|
||||||
cd $WORKING_DIR &&
|
cd $WORKING_DIR &&
|
||||||
sed -i '/jehanne/b; /ELF_TARGET_ID/,/elf_backend_can_gc_sections/s/0x200000/0x1000 \/\/ jehanne hack/g' src/binutils/bfd/elf64-x86-64.c &&
|
sed -i '/jehanne/b; /ELF_TARGET_ID/,/elf_backend_can_gc_sections/s/0x200000/0x1000 \/\/ jehanne hack/g' src/binutils/bfd/elf64-x86-64.c &&
|
||||||
sed -i '/jehanne/b; s/| midnightbsd\*/| midnightbsd* | jehanne*/g' src/binutils/config.sub &&
|
sed -i '/jehanne/b; s/| midnightbsd\*/| midnightbsd* | jehanne*/g' src/binutils/config.sub &&
|
||||||
|
sed -i 's/inline/static inline/g' src/binutils/libctf/swap.h &&
|
||||||
dynpatch 'binutils/bfd/config.bfd' '\# END OF targmatch.h' &&
|
dynpatch 'binutils/bfd/config.bfd' '\# END OF targmatch.h' &&
|
||||||
dynpatch 'binutils/gas/configure.tgt' ' i386-\*-darwin\*)' &&
|
dynpatch 'binutils/gas/configure.tgt' ' i386-\*-darwin\*)' &&
|
||||||
( grep -q jehanne src/binutils/ld/configure.tgt || patch -p1 < $CROSS_DIR/patch/binutils/ld/configure.tgt ) &&
|
( grep -q jehanne src/binutils/ld/configure.tgt || patch -p1 < $CROSS_DIR/patch/binutils/ld/configure.tgt ) &&
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"CrossCompiledPackages": {
|
|
||||||
"Env": [
|
|
||||||
"CROSS_PKGS_BUILD=1"
|
|
||||||
],
|
|
||||||
"Pre": [
|
|
||||||
"./newlib/build.sh",
|
|
||||||
"./mksh/build.sh",
|
|
||||||
"./gcc/build.sh"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
10
cross/pkgs/build.sh
Executable file
10
cross/pkgs/build.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export IFS="$ifs"
|
||||||
|
export CROSS_PKGS_BUILD=1
|
||||||
|
export CFLAGS=''
|
||||||
|
export CC=''
|
||||||
|
|
||||||
|
./newlib/build.sh
|
||||||
|
./mksh/build.sh
|
||||||
|
./gcc/build.sh
|
@ -50,7 +50,7 @@ ln -s `which echo` $JEHANNE/hacking/bin/makeinfo
|
|||||||
libtool --version >> /dev/null
|
libtool --version >> /dev/null
|
||||||
failOnError $? "libtool installation check"
|
failOnError $? "libtool installation check"
|
||||||
|
|
||||||
(cd $JEHANNE_TOOLCHAIN/src && fetch) >> $LOG
|
(cd $JEHANNE_TOOLCHAIN/src && ./fetch.sh) >> $LOG
|
||||||
failOnError $? "fetching sources"
|
failOnError $? "fetching sources"
|
||||||
|
|
||||||
|
|
||||||
|
45
cross/pkgs/gcc/src/fetch.sh
Executable file
45
cross/pkgs/gcc/src/fetch.sh
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
download () {
|
||||||
|
TARGET=$(basename $1)
|
||||||
|
if [ -f $TARGET ]; then
|
||||||
|
echo "fetch: skip $TARGET (already present)"
|
||||||
|
elif command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -s --fail "$1" > $TARGET
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
wget -O- "$1" > $TARGET
|
||||||
|
else
|
||||||
|
echo "ERROR: Unable to find either curl or wget" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract () {
|
||||||
|
TARGET=$1
|
||||||
|
ARCHIVE=$2
|
||||||
|
if [ -d $TARGET ]; then
|
||||||
|
echo "fetch: skip $TARGET (already present)"
|
||||||
|
else
|
||||||
|
mkdir -p $TARGET
|
||||||
|
(cd $TARGET && tar xf ../$ARCHIVE --strip-components=1)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "fetch: downloading..."
|
||||||
|
download 'https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2'
|
||||||
|
download 'https://www.mpfr.org/mpfr-4.0.1/mpfr-4.0.1.tar.bz2'
|
||||||
|
download 'https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz'
|
||||||
|
download 'http://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2'
|
||||||
|
download 'https://ftp.gnu.org/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.gz'
|
||||||
|
|
||||||
|
echo "fetch: check sum..."
|
||||||
|
sha256sum -c sha256sum.txt
|
||||||
|
|
||||||
|
echo "fetch: extract archive..."
|
||||||
|
extract libgmp gmp-6.1.2.tar.bz2
|
||||||
|
extract libmpfr mpfr-4.0.1.tar.bz2
|
||||||
|
extract libmpc mpc-1.1.0.tar.gz
|
||||||
|
extract binutils binutils-2.33.1.tar.bz2
|
||||||
|
extract gcc gcc-9.2.0.tar.gz
|
||||||
|
|
||||||
|
echo "fetch: done."
|
5
cross/pkgs/gcc/src/sha256sum.txt
Normal file
5
cross/pkgs/gcc/src/sha256sum.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
0cb4843da15a65a953907c96bad658283f3c4419d6bcc56bf2789db16306adb2 binutils-2.33.1.tar.bz2
|
||||||
|
a931a750d6feadacbeecb321d73925cd5ebb6dfa7eff0802984af3aef63759f4 gcc-9.2.0.tar.gz
|
||||||
|
5275bb04f4863a13516b2f39392ac5e272f5e1bb8057b18aec1c9b79d73d8fb2 gmp-6.1.2.tar.bz2
|
||||||
|
6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e mpc-1.1.0.tar.gz
|
||||||
|
a4d97610ba8579d380b384b225187c250ef88cfe1d5e7226b89519374209b86b mpfr-4.0.1.tar.bz2
|
@ -1,53 +0,0 @@
|
|||||||
{
|
|
||||||
"libgmp" : {
|
|
||||||
"Upstream":"https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2",
|
|
||||||
"Digest": {
|
|
||||||
"sha256":"5275bb04f4863a13516b2f39392ac5e272f5e1bb8057b18aec1c9b79d73d8fb2"
|
|
||||||
},
|
|
||||||
"Compress":"bzip2",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libmpfr" : {
|
|
||||||
"Upstream":"https://www.mpfr.org/mpfr-4.0.1/mpfr-4.0.1.tar.bz2",
|
|
||||||
"Digest": {
|
|
||||||
"sha256":"a4d97610ba8579d380b384b225187c250ef88cfe1d5e7226b89519374209b86b"
|
|
||||||
},
|
|
||||||
"Compress":"bzip2",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"libmpc" : {
|
|
||||||
"Upstream":"https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz",
|
|
||||||
"Digest": {
|
|
||||||
"sha256":"6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e"
|
|
||||||
},
|
|
||||||
"Compress":"gzip",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"binutils": {
|
|
||||||
"Upstream":"http://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2",
|
|
||||||
"Digest": {
|
|
||||||
"sha256":"0cb4843da15a65a953907c96bad658283f3c4419d6bcc56bf2789db16306adb2"
|
|
||||||
},
|
|
||||||
"Compress":"bzip2",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gcc": {
|
|
||||||
"Upstream":"https://ftp.gnu.org/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.gz",
|
|
||||||
"Digest": {
|
|
||||||
"sha256":"a931a750d6feadacbeecb321d73925cd5ebb6dfa7eff0802984af3aef63759f4"
|
|
||||||
},
|
|
||||||
"Compress":"gzip",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
45
cross/src/fetch.sh
Executable file
45
cross/src/fetch.sh
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
download () {
|
||||||
|
TARGET=$(basename $1)
|
||||||
|
if [ -f $TARGET ]; then
|
||||||
|
echo "fetch: skip $TARGET (already present)"
|
||||||
|
elif command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -s --fail "$1" > $TARGET
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
wget -O- "$1" > $TARGET
|
||||||
|
else
|
||||||
|
echo "ERROR: Unable to find either curl or wget" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract () {
|
||||||
|
TARGET=$1
|
||||||
|
ARCHIVE=$2
|
||||||
|
if [ -d $TARGET ]; then
|
||||||
|
echo "fetch: skip $TARGET (already present)"
|
||||||
|
else
|
||||||
|
mkdir -p $TARGET
|
||||||
|
(cd $TARGET && tar xf ../$ARCHIVE --strip-components=1)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "fetch: downloading..."
|
||||||
|
download 'https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2'
|
||||||
|
download 'https://www.mpfr.org/mpfr-4.0.1/mpfr-4.0.1.tar.bz2'
|
||||||
|
download 'https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz'
|
||||||
|
download 'http://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2'
|
||||||
|
download 'https://ftp.gnu.org/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.gz'
|
||||||
|
|
||||||
|
echo "fetch: check sum..."
|
||||||
|
sha256sum -c sha256sum.txt
|
||||||
|
|
||||||
|
echo "fetch: extract archive..."
|
||||||
|
extract libgmp gmp-6.1.2.tar.bz2
|
||||||
|
extract libmpfr mpfr-4.0.1.tar.bz2
|
||||||
|
extract libmpc mpc-1.1.0.tar.gz
|
||||||
|
extract binutils binutils-2.33.1.tar.bz2
|
||||||
|
extract gcc gcc-9.2.0.tar.gz
|
||||||
|
|
||||||
|
echo "fetch: done."
|
5
cross/src/sha256sum.txt
Normal file
5
cross/src/sha256sum.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
0cb4843da15a65a953907c96bad658283f3c4419d6bcc56bf2789db16306adb2 binutils-2.33.1.tar.bz2
|
||||||
|
a931a750d6feadacbeecb321d73925cd5ebb6dfa7eff0802984af3aef63759f4 gcc-9.2.0.tar.gz
|
||||||
|
5275bb04f4863a13516b2f39392ac5e272f5e1bb8057b18aec1c9b79d73d8fb2 gmp-6.1.2.tar.bz2
|
||||||
|
6985c538143c1208dcb1ac42cedad6ff52e267b47e5f970183a3e75125b43c2e mpc-1.1.0.tar.gz
|
||||||
|
a4d97610ba8579d380b384b225187c250ef88cfe1d5e7226b89519374209b86b mpfr-4.0.1.tar.bz2
|
10
devshell.sh
10
devshell.sh
@ -9,10 +9,16 @@ REPONAME=`basename $JEHANNE`
|
|||||||
JEHANNE_TOOLCHAIN=`dirname $JEHANNE`
|
JEHANNE_TOOLCHAIN=`dirname $JEHANNE`
|
||||||
JEHANNE_TOOLCHAIN="$JEHANNE_TOOLCHAIN/$REPONAME.TOOLCHAIN"
|
JEHANNE_TOOLCHAIN="$JEHANNE_TOOLCHAIN/$REPONAME.TOOLCHAIN"
|
||||||
export JEHANNE_TOOLCHAIN
|
export JEHANNE_TOOLCHAIN
|
||||||
|
JEHANNE_TOOLCHAIN_CROSS="$JEHANNE_TOOLCHAIN/cross"
|
||||||
|
export JEHANNE_TOOLCHAIN_CROSS
|
||||||
|
JEHANNE_HACKING=$JEHANNE/hacking
|
||||||
|
export JEHANNE_HACKING
|
||||||
|
|
||||||
export PATH="$JEHANNE/hacking/bin:$PATH"
|
|
||||||
export PATH="$JEHANNE_TOOLCHAIN/cross/posix/bin:$PATH"
|
export PATH="$JEHANNE_TOOLCHAIN/cross/posix/bin:$PATH"
|
||||||
#export CPATH="$JEHANNE_TOOLCHAIN/cross/posix/lib/gcc/x86_64-jehanne/9.2.0/include:$JEHANNE_TOOLCHAIN/cross/posix/lib/gcc/x86_64-jehanne/9.2.0/include-fixed"
|
export PATH="$JEHANNE_HACKING/bin:$PATH"
|
||||||
|
export PATH_CLONE=$PATH
|
||||||
|
|
||||||
|
|
||||||
export ARCH=amd64
|
export ARCH=amd64
|
||||||
|
|
||||||
export TOOLPREFIX=x86_64-jehanne-
|
export TOOLPREFIX=x86_64-jehanne-
|
||||||
|
51
rcmain
Normal file
51
rcmain
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# rcmain: Plan 9 on Unix version
|
||||||
|
if(~ $#home 0) home=$HOME
|
||||||
|
if(~ $#home 0) home=/
|
||||||
|
if(~ $#ifs 0) ifs='
|
||||||
|
'
|
||||||
|
switch($#prompt){
|
||||||
|
case 0
|
||||||
|
prompt=('% ' ' ')
|
||||||
|
case 1
|
||||||
|
prompt=($prompt ' ')
|
||||||
|
}
|
||||||
|
if(~ $rcname ?.out ?.rc */?.rc */?.out) prompt=('broken! ' ' ')
|
||||||
|
if(flag p) path=(/bin /usr/bin)
|
||||||
|
if not{
|
||||||
|
finit
|
||||||
|
# should be taken care of by rc now, but leave just in case
|
||||||
|
}
|
||||||
|
fn sigexit
|
||||||
|
if(! ~ $#cflag 0){
|
||||||
|
if(flag l && test -r $home/lib/profile) . $home/lib/profile
|
||||||
|
status=''
|
||||||
|
eval $cflag
|
||||||
|
exit $status
|
||||||
|
}
|
||||||
|
if(flag i){
|
||||||
|
if(~ $termprog 9term || ~ $termprog win){
|
||||||
|
fn cd {
|
||||||
|
# builtin cd $1 && flag i && awd
|
||||||
|
# is not sufficient when running in a subshell
|
||||||
|
# that is rc -e (like mk uses!)
|
||||||
|
if(builtin cd $1){
|
||||||
|
if(flag i) $PLAN9/bin/9 awd || status=''
|
||||||
|
status=''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$PLAN9/bin/9 awd
|
||||||
|
}
|
||||||
|
if(flag l && test -r $home/lib/profile) . $home/lib/profile
|
||||||
|
status=''
|
||||||
|
if(! ~ $#* 0) . $*
|
||||||
|
. -i '/dev/stdin'
|
||||||
|
exit $status
|
||||||
|
}
|
||||||
|
if(flag l && test -r $home/lib/profile) . $home/lib/profile
|
||||||
|
if(~ $#* 0){
|
||||||
|
. /dev/stdin
|
||||||
|
exit $status
|
||||||
|
}
|
||||||
|
status=''
|
||||||
|
. $*
|
||||||
|
exit $status
|
@ -13,8 +13,7 @@ fi
|
|||||||
|
|
||||||
trap : 2
|
trap : 2
|
||||||
|
|
||||||
$JEHANNE/hacking/bin/ufs -root=$JEHANNE &
|
$JEHANNE/hacking/bin/nc -p 5640 -l -e $JEHANNE/hacking/bin/start-u9fs.sh &
|
||||||
# To debug ufs add: -d 5 > $JEHANNE/../ufs.log 2>&1
|
|
||||||
ufspid=$!
|
ufspid=$!
|
||||||
|
|
||||||
export machineflag=pc
|
export machineflag=pc
|
||||||
@ -53,7 +52,7 @@ QEMU_USER=`whoami`
|
|||||||
|
|
||||||
cd $KERNDIR
|
cd $KERNDIR
|
||||||
read -r cmd <<EOF
|
read -r cmd <<EOF
|
||||||
$kvmdo qemu-system-x86_64 -s -cpu Haswell -smp $NCPU -m 2048 $kvmflag \
|
$kvmdo qemu-system-x86_64 -s -cpu max -smp $NCPU -m 2048 $kvmflag \
|
||||||
-rtc clock=vm \
|
-rtc clock=vm \
|
||||||
-no-reboot -serial mon:stdio \
|
-no-reboot -serial mon:stdio \
|
||||||
--machine $machineflag \
|
--machine $machineflag \
|
||||||
@ -74,5 +73,5 @@ EOF
|
|||||||
echo $cmd
|
echo $cmd
|
||||||
eval $cmd
|
eval $cmd
|
||||||
|
|
||||||
kill $ufspid
|
# kill $ufspid # not needed anymore thank to netcat
|
||||||
wait
|
wait
|
||||||
|
@ -1,669 +0,0 @@
|
|||||||
// Build builds code as directed by json files.
|
|
||||||
// We slurp in the JSON, and recursively process includes.
|
|
||||||
// At the end, we issue a single cc command for all the files.
|
|
||||||
// Compilers are fast.
|
|
||||||
//
|
|
||||||
// ENVIRONMENT
|
|
||||||
//
|
|
||||||
// Needed: JEHANNE, ARCH
|
|
||||||
//
|
|
||||||
// JEHANNE should point to a Jehanne root.
|
|
||||||
// Currently only "amd64" is a valid ARCH.
|
|
||||||
// A best-effort to autodetect the Jehanne root is made if not explicitly set.
|
|
||||||
//
|
|
||||||
// Optional: CC, AR, LD, RANLIB, STRIP, SH, TOOLPREFIX
|
|
||||||
//
|
|
||||||
// These all control how the needed tools are found.
|
|
||||||
//
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type kernconfig struct {
|
|
||||||
Code []string
|
|
||||||
Dev []string
|
|
||||||
Ip []string
|
|
||||||
Link []string
|
|
||||||
Sd []string
|
|
||||||
Uart []string
|
|
||||||
VGA []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type kernel struct {
|
|
||||||
CodeFile string
|
|
||||||
Systab string
|
|
||||||
Config kernconfig
|
|
||||||
Ramfiles map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
type build struct {
|
|
||||||
// jsons is unexported so can not be set in a .json file
|
|
||||||
jsons map[string]bool
|
|
||||||
path string
|
|
||||||
name string
|
|
||||||
// Projects name a whole subproject which is built independently of
|
|
||||||
// this one. We'll need to be able to use environment variables at some point.
|
|
||||||
Projects []string
|
|
||||||
Pre []string
|
|
||||||
Post []string
|
|
||||||
Cflags []string
|
|
||||||
Oflags []string
|
|
||||||
Include []string
|
|
||||||
SourceFiles []string
|
|
||||||
ObjectFiles []string
|
|
||||||
Libs []string
|
|
||||||
Env []string
|
|
||||||
// cmd's
|
|
||||||
SourceFilesCmd []string
|
|
||||||
// Targets.
|
|
||||||
Program string
|
|
||||||
Library string
|
|
||||||
Install string // where to place the resulting binary/lib
|
|
||||||
Kernel *kernel
|
|
||||||
}
|
|
||||||
|
|
||||||
type buildfile map[string]build
|
|
||||||
|
|
||||||
// UnmarshalJSON works like the stdlib unmarshal would, except it adjusts all
|
|
||||||
// paths.
|
|
||||||
func (bf *buildfile) UnmarshalJSON(s []byte) error {
|
|
||||||
r := make(map[string]build)
|
|
||||||
if err := json.Unmarshal(s, &r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, b := range r {
|
|
||||||
// we're getting a copy of the struct, remember.
|
|
||||||
b.jsons = make(map[string]bool)
|
|
||||||
b.Projects = adjust(b.Projects)
|
|
||||||
b.Libs = adjust(b.Libs)
|
|
||||||
b.Cflags = adjust(b.Cflags)
|
|
||||||
b.SourceFiles = b.SourceFiles
|
|
||||||
b.SourceFilesCmd = b.SourceFilesCmd
|
|
||||||
b.ObjectFiles = b.ObjectFiles
|
|
||||||
b.Include = adjust(b.Include)
|
|
||||||
b.Install = fromRoot(b.Install)
|
|
||||||
for i, e := range b.Env {
|
|
||||||
b.Env[i] = os.ExpandEnv(e)
|
|
||||||
}
|
|
||||||
r[k] = b
|
|
||||||
}
|
|
||||||
*bf = r
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
cwd string
|
|
||||||
jehanne string
|
|
||||||
regexpAll = []*regexp.Regexp{regexp.MustCompile(".")}
|
|
||||||
|
|
||||||
// findTools looks at all env vars and absolutizes these paths
|
|
||||||
// also respects TOOLPREFIX
|
|
||||||
tools = map[string]string{
|
|
||||||
"cc": "gcc",
|
|
||||||
"ar": "ar",
|
|
||||||
"ld": "ld",
|
|
||||||
"ranlib": "ranlib",
|
|
||||||
"strip": "strip",
|
|
||||||
"sh": "sh",
|
|
||||||
}
|
|
||||||
arch = map[string]bool{
|
|
||||||
"amd64": true,
|
|
||||||
}
|
|
||||||
debugPrint = flag.Bool("debug", false, "enable debug prints")
|
|
||||||
shellhack = flag.Bool("shellhack", false, "spawn every command in a shell (forced on if LD_PRELOAD is set)")
|
|
||||||
)
|
|
||||||
|
|
||||||
func debug(fmt string, s ...interface{}) {
|
|
||||||
if *debugPrint {
|
|
||||||
log.Printf(fmt, s...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fail with message, if err is not nil
|
|
||||||
func failOn(err error) {
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("%v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValueInList(value string, list []string) bool {
|
|
||||||
for _, v := range list {
|
|
||||||
if v == value {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func adjust(s []string) []string {
|
|
||||||
for i, v := range s {
|
|
||||||
s[i] = fromRoot(v)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildEnv(b *build) func(string) string{
|
|
||||||
return func(v string) string {
|
|
||||||
search := v + "="
|
|
||||||
for _, s := range b.Env {
|
|
||||||
if strings.Index(s, search) == 0 {
|
|
||||||
return strings.Replace(s, search, "", 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return os.Getenv(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the given absolute path as an absolute path rooted at the jehanne tree.
|
|
||||||
func fromRoot(p string) string {
|
|
||||||
p = os.ExpandEnv(p)
|
|
||||||
if path.IsAbs(p) {
|
|
||||||
return path.Join(jehanne, p)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sh sends cmd to a shell. It's needed to enable $LD_PRELOAD tricks,
|
|
||||||
// see https://github.com/Harvey-OS/jehanne/issues/8#issuecomment-131235178
|
|
||||||
func sh(cmd *exec.Cmd) {
|
|
||||||
shell := exec.Command(tools["sh"])
|
|
||||||
shell.Env = cmd.Env
|
|
||||||
|
|
||||||
if cmd.Args[0] == tools["sh"] && cmd.Args[1] == "-c" {
|
|
||||||
cmd.Args = cmd.Args[2:]
|
|
||||||
}
|
|
||||||
commandString := strings.Join(cmd.Args, " ")
|
|
||||||
if shStdin, e := shell.StdinPipe(); e == nil {
|
|
||||||
go func() {
|
|
||||||
defer shStdin.Close()
|
|
||||||
io.WriteString(shStdin, commandString)
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
log.Fatalf("cannot pipe [%v] to %s: %v", commandString, tools["sh"], e)
|
|
||||||
}
|
|
||||||
shell.Stderr = os.Stderr
|
|
||||||
shell.Stdout = os.Stdout
|
|
||||||
|
|
||||||
debug("%q | sh\n", commandString)
|
|
||||||
failOn(shell.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeKernel(k *kernel, defaults *kernel) *kernel {
|
|
||||||
if k == nil {
|
|
||||||
return defaults
|
|
||||||
}
|
|
||||||
if defaults == nil {
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
|
|
||||||
// The custom kernel Code will be added after the default from includes
|
|
||||||
// so that it has a chance to change de default behaviour.
|
|
||||||
k.Config.Code = append(defaults.Config.Code, k.Config.Code...)
|
|
||||||
|
|
||||||
k.Config.Dev = append(k.Config.Dev, defaults.Config.Dev...)
|
|
||||||
k.Config.Ip = append(k.Config.Ip, defaults.Config.Ip...)
|
|
||||||
k.Config.Link = append(k.Config.Link, defaults.Config.Link...)
|
|
||||||
k.Config.Sd = append(k.Config.Sd, defaults.Config.Sd...)
|
|
||||||
k.Config.Uart = append(k.Config.Uart, defaults.Config.Uart...)
|
|
||||||
k.Config.VGA = append(k.Config.VGA, defaults.Config.VGA...)
|
|
||||||
|
|
||||||
if k.CodeFile == "" {
|
|
||||||
k.CodeFile = defaults.CodeFile
|
|
||||||
}
|
|
||||||
if k.Systab == "" {
|
|
||||||
k.Systab = defaults.Systab
|
|
||||||
}
|
|
||||||
for name, path := range defaults.Ramfiles {
|
|
||||||
if _, ok := k.Ramfiles[name]; ok == false {
|
|
||||||
k.Ramfiles[name] = path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
|
|
||||||
func include(f string, b *build) {
|
|
||||||
if b.jsons[f] {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b.jsons[f] = true
|
|
||||||
log.Printf("Including %v", f)
|
|
||||||
d, err := ioutil.ReadFile(f)
|
|
||||||
failOn(err)
|
|
||||||
var builds buildfile
|
|
||||||
failOn(json.Unmarshal(d, &builds))
|
|
||||||
|
|
||||||
for n, build := range builds {
|
|
||||||
log.Printf("Merging %v", n)
|
|
||||||
b.SourceFiles = append(b.SourceFiles, build.SourceFiles...)
|
|
||||||
b.Cflags = append(b.Cflags, build.Cflags...)
|
|
||||||
b.Oflags = append(b.Oflags, build.Oflags...)
|
|
||||||
b.Pre = append(b.Pre, build.Pre...)
|
|
||||||
b.Post = append(b.Post, build.Post...)
|
|
||||||
b.Libs = append(b.Libs, build.Libs...)
|
|
||||||
b.Projects = append(b.Projects, build.Projects...)
|
|
||||||
b.Env = append(b.Env, build.Env...)
|
|
||||||
b.SourceFilesCmd = append(b.SourceFilesCmd, build.SourceFilesCmd...)
|
|
||||||
b.Program += build.Program
|
|
||||||
b.Library += build.Library
|
|
||||||
b.Kernel = mergeKernel(b.Kernel, build.Kernel)
|
|
||||||
if build.Install != "" {
|
|
||||||
if b.Install != "" {
|
|
||||||
log.Fatalf("In file %s (target %s) included by %s (target %s): redefined Install.", f, n, build.path, build.name)
|
|
||||||
}
|
|
||||||
b.Install = build.Install
|
|
||||||
}
|
|
||||||
b.ObjectFiles = append(b.ObjectFiles, build.ObjectFiles...)
|
|
||||||
// For each source file, assume we create an object file with the last char replaced
|
|
||||||
// with 'o'. We can get smarter later.
|
|
||||||
for _, v := range build.SourceFiles {
|
|
||||||
f := path.Base(v)
|
|
||||||
o := f[:len(f)-1] + "o"
|
|
||||||
b.ObjectFiles = append(b.ObjectFiles, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range build.Include {
|
|
||||||
if !path.IsAbs(v) {
|
|
||||||
wd := path.Dir(f)
|
|
||||||
v = path.Join(wd, v)
|
|
||||||
}
|
|
||||||
include(v, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendIfMissing(s []string, v string) []string {
|
|
||||||
for _, a := range s {
|
|
||||||
if a == v {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(s, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func process(f string, r []*regexp.Regexp) []build {
|
|
||||||
log.Printf("Processing %v", f)
|
|
||||||
var builds buildfile
|
|
||||||
var results []build
|
|
||||||
d, err := ioutil.ReadFile(f)
|
|
||||||
failOn(err)
|
|
||||||
failOn(json.Unmarshal(d, &builds))
|
|
||||||
|
|
||||||
// Sort keys alphabetically (GoLang does not preserve the JSON order)
|
|
||||||
var keys []string
|
|
||||||
for n := range builds {
|
|
||||||
keys = append(keys, n)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, n := range keys {
|
|
||||||
build := builds[n]
|
|
||||||
build.name = n
|
|
||||||
build.jsons = make(map[string]bool)
|
|
||||||
skip := true
|
|
||||||
for _, re := range r {
|
|
||||||
if re.MatchString(build.name) {
|
|
||||||
skip = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if skip {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Printf("Run %v", build.name)
|
|
||||||
build.jsons[f] = true
|
|
||||||
build.path = path.Dir(f)
|
|
||||||
|
|
||||||
// For each source file, assume we create an object file with the last char replaced
|
|
||||||
// with 'o'. We can get smarter later.
|
|
||||||
for _, v := range build.SourceFiles {
|
|
||||||
f := path.Base(v)
|
|
||||||
o := f[:len(f)-1] + "o"
|
|
||||||
build.ObjectFiles = appendIfMissing(build.ObjectFiles, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range build.Include {
|
|
||||||
include(v, &build)
|
|
||||||
}
|
|
||||||
results = append(results, build)
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildkernel(b *build) {
|
|
||||||
if b.Kernel == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
envFunc := buildEnv(b)
|
|
||||||
for name, path := range b.Kernel.Ramfiles {
|
|
||||||
b.Kernel.Ramfiles[name] = os.Expand(path, envFunc);
|
|
||||||
}
|
|
||||||
codebuf := confcode(b.path, b.Kernel)
|
|
||||||
if b.Kernel.CodeFile == "" {
|
|
||||||
log.Fatalf("Missing Kernel.CodeFile in %v\n", b.path)
|
|
||||||
}
|
|
||||||
failOn(ioutil.WriteFile(b.Kernel.CodeFile, codebuf, 0666))
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapInQuote(args []string) []string {
|
|
||||||
var res []string
|
|
||||||
for _, a := range(args){
|
|
||||||
if strings.Contains(a, "=") {
|
|
||||||
res = append(res, "'" + a + "'")
|
|
||||||
} else {
|
|
||||||
res = append(res, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertLibPathsToArgs(b *build) []string {
|
|
||||||
libLocations := make([]string, 0)
|
|
||||||
args := make([]string, 0)
|
|
||||||
defaultLibLocation := fromRoot("/arch/$ARCH/lib")
|
|
||||||
for _, lib := range b.Libs {
|
|
||||||
ldir := filepath.Dir(lib)
|
|
||||||
if ldir != defaultLibLocation {
|
|
||||||
if !isValueInList(ldir, libLocations) {
|
|
||||||
libLocations = append(libLocations, ldir)
|
|
||||||
args = append(args, "-L", ldir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lib = strings.Replace(lib, ldir + "/lib", "-l", 1)
|
|
||||||
lib = strings.Replace(lib, ".a", "", 1)
|
|
||||||
args = append(args, lib)
|
|
||||||
}
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
func compile(b *build) {
|
|
||||||
log.Printf("Building %s\n", b.name)
|
|
||||||
// N.B. Plan 9 has a very well defined include structure, just three things:
|
|
||||||
// /amd64/include, /sys/include, .
|
|
||||||
args := b.SourceFiles
|
|
||||||
args = append(args, b.Cflags...)
|
|
||||||
if !isValueInList("-c", b.Cflags) {
|
|
||||||
args = append(args, convertLibPathsToArgs(b)...)
|
|
||||||
args = append(args, b.Oflags...)
|
|
||||||
}
|
|
||||||
if len(b.SourceFilesCmd) > 0 {
|
|
||||||
for _, i := range b.SourceFilesCmd {
|
|
||||||
largs := make([]string, 3)
|
|
||||||
largs[0] = i
|
|
||||||
largs[1] = "-o"
|
|
||||||
largs[2] = strings.Replace(filepath.Base(i), filepath.Ext(i), "", 1)
|
|
||||||
cmd := exec.Command(tools["cc"], append(largs, args...)...)
|
|
||||||
run(b, *shellhack, cmd)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !isValueInList("-c", b.Cflags) {
|
|
||||||
args = append(args, "-o", b.Program)
|
|
||||||
}
|
|
||||||
cmd := exec.Command(tools["cc"], args...)
|
|
||||||
run(b, *shellhack, cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func link(b *build) {
|
|
||||||
if !isValueInList("-c", b.Cflags) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Linking %s\n", b.name)
|
|
||||||
if len(b.SourceFilesCmd) > 0 {
|
|
||||||
for _, n := range b.SourceFilesCmd {
|
|
||||||
// Split off the last element of the file
|
|
||||||
var ext = filepath.Ext(n)
|
|
||||||
if len(ext) == 0 {
|
|
||||||
log.Fatalf("refusing to overwrite extension-less source file %v", n)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
n = n[:len(n)-len(ext)]
|
|
||||||
f := path.Base(n)
|
|
||||||
o := f[:len(f)] + ".o"
|
|
||||||
args := []string{"-o", n, o}
|
|
||||||
args = append(args, b.Oflags...)
|
|
||||||
args = append(args, b.Libs...)
|
|
||||||
run(b, *shellhack, exec.Command(tools["ld"], args...))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
args := []string{"-o", b.Program}
|
|
||||||
args = append(args, b.ObjectFiles...)
|
|
||||||
args = append(args, b.Oflags...)
|
|
||||||
args = append(args, b.Libs...)
|
|
||||||
run(b, *shellhack, exec.Command(tools["ld"], args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func install(b *build) {
|
|
||||||
if b.Install == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Installing %s\n", b.name)
|
|
||||||
failOn(os.MkdirAll(b.Install, 0755))
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case len(b.SourceFilesCmd) > 0:
|
|
||||||
for _, n := range b.SourceFilesCmd {
|
|
||||||
ext := filepath.Ext(n)
|
|
||||||
exe := n[:len(n)-len(ext)]
|
|
||||||
move(exe, b.Install)
|
|
||||||
}
|
|
||||||
case len(b.Program) > 0:
|
|
||||||
move(b.Program, b.Install)
|
|
||||||
case len(b.Library) > 0:
|
|
||||||
ofiles := []string{}
|
|
||||||
for _, o := range b.ObjectFiles {
|
|
||||||
os.Rename(o, b.Library + "-" + o)
|
|
||||||
ofiles = append(ofiles, b.Library + "-" + o)
|
|
||||||
}
|
|
||||||
libpath := path.Join(b.Install, b.Library)
|
|
||||||
|
|
||||||
args := append([]string{"-rs", libpath}, ofiles...)
|
|
||||||
run(b, *shellhack, exec.Command(tools["ar"], args...))
|
|
||||||
run(b, *shellhack, exec.Command(tools["ranlib"], libpath))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func move(from, to string) {
|
|
||||||
final := path.Join(to, from)
|
|
||||||
log.Printf("move %s %s\n", from, final)
|
|
||||||
_ = os.Remove(final)
|
|
||||||
failOn(os.Link(from, final))
|
|
||||||
failOn(os.Remove(from))
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(b *build, pipe bool, cmd *exec.Cmd) {
|
|
||||||
if b != nil {
|
|
||||||
cmd.Env = append(os.Environ(), b.Env...)
|
|
||||||
}
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
if pipe {
|
|
||||||
// Sh sends cmd to a shell. It's needed to enable $LD_PRELOAD tricks, see https://github.com/Harvey-OS/jehanne/issues/8#issuecomment-131235178
|
|
||||||
shell := exec.Command(tools["sh"])
|
|
||||||
shell.Env = cmd.Env
|
|
||||||
shell.Stderr = os.Stderr
|
|
||||||
shell.Stdout = os.Stdout
|
|
||||||
|
|
||||||
commandString := cmd.Args[0]
|
|
||||||
commandString += " " + strings.Join(wrapInQuote(cmd.Args[1:]), " ")
|
|
||||||
shStdin, err := shell.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("cannot pipe [%v] to %s: %v", commandString, tools["sh"], err)
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
defer shStdin.Close()
|
|
||||||
io.WriteString(shStdin, commandString)
|
|
||||||
}()
|
|
||||||
|
|
||||||
log.Printf("%q | %s\n", commandString, tools["sh"])
|
|
||||||
failOn(shell.Run())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Println(strings.Join(cmd.Args, " "))
|
|
||||||
failOn(cmd.Run())
|
|
||||||
}
|
|
||||||
|
|
||||||
func projects(b *build, r []*regexp.Regexp) {
|
|
||||||
for _, v := range b.Projects {
|
|
||||||
f, _ := findBuildfile(v)
|
|
||||||
log.Printf("Doing %s\n", f)
|
|
||||||
project(f, r, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// assumes we are in the wd of the project.
|
|
||||||
func project(bf string, which []*regexp.Regexp, container *build) {
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
failOn(err)
|
|
||||||
debug("Start new project cwd is %v", cwd)
|
|
||||||
defer os.Chdir(cwd)
|
|
||||||
dir := path.Dir(bf)
|
|
||||||
root := path.Base(bf)
|
|
||||||
debug("CD to %v and build using %v", dir, root)
|
|
||||||
failOn(os.Chdir(dir))
|
|
||||||
builds := process(root, which)
|
|
||||||
debug("Processing %v: %d target", root, len(builds))
|
|
||||||
for _, b := range builds {
|
|
||||||
debug("Processing %v: %v", b.name, b)
|
|
||||||
if container != nil {
|
|
||||||
b.Env = append(container.Env, b.Env...)
|
|
||||||
}
|
|
||||||
projects(&b, regexpAll)
|
|
||||||
for _, c := range b.Pre {
|
|
||||||
// this is a hack: we just pass the command through as an exec.Cmd
|
|
||||||
run(&b, true, exec.Command(c))
|
|
||||||
}
|
|
||||||
envFunc := buildEnv(&b);
|
|
||||||
b.Program = os.Expand(b.Program, envFunc)
|
|
||||||
for i, s := range b.SourceFiles {
|
|
||||||
b.SourceFiles[i] = fromRoot(os.Expand(s, envFunc));
|
|
||||||
}
|
|
||||||
for i, s := range b.SourceFilesCmd {
|
|
||||||
b.SourceFilesCmd[i] = fromRoot(os.Expand(s, envFunc));
|
|
||||||
}
|
|
||||||
for i, s := range b.ObjectFiles {
|
|
||||||
b.ObjectFiles[i] = fromRoot(os.Expand(s, envFunc));
|
|
||||||
}
|
|
||||||
buildkernel(&b)
|
|
||||||
if len(b.SourceFiles) > 0 || len(b.SourceFilesCmd) > 0 {
|
|
||||||
compile(&b)
|
|
||||||
}
|
|
||||||
if b.Program != "" || len(b.SourceFilesCmd) > 0 {
|
|
||||||
link(&b)
|
|
||||||
}
|
|
||||||
install(&b)
|
|
||||||
for _, c := range b.Post {
|
|
||||||
run(&b, true, exec.Command(c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// A small amount of setup is done in the paths*.go files. They are
|
|
||||||
// OS-specific path setup/manipulation. "jehanne" is set there and $PATH is
|
|
||||||
// adjusted.
|
|
||||||
var err error
|
|
||||||
findTools(os.Getenv("TOOLPREFIX"))
|
|
||||||
flag.Parse()
|
|
||||||
cwd, err = os.Getwd()
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
a := os.Getenv("ARCH")
|
|
||||||
if a == "" || !arch[a] {
|
|
||||||
s := []string{}
|
|
||||||
for i := range arch {
|
|
||||||
s = append(s, i)
|
|
||||||
}
|
|
||||||
log.Fatalf("You need to set the ARCH environment variable from: %v", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure this is exported, in case we used a default value
|
|
||||||
os.Setenv("JEHANNE", jehanne)
|
|
||||||
|
|
||||||
if os.Getenv("LD_PRELOAD") != "" {
|
|
||||||
log.Println("Using shellhack")
|
|
||||||
*shellhack = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no args, assume 'build.json'
|
|
||||||
// Otherwise the first argument is either
|
|
||||||
// - the path to a json file
|
|
||||||
// - a directory containing a 'build.json' file
|
|
||||||
// - a regular expression to apply assuming 'build.json'
|
|
||||||
// Further arguments are regular expressions.
|
|
||||||
consumedArgs := 0;
|
|
||||||
bf := ""
|
|
||||||
if len(flag.Args()) == 0 {
|
|
||||||
f, err := findBuildfile("build.json")
|
|
||||||
failOn(err)
|
|
||||||
bf = f
|
|
||||||
} else {
|
|
||||||
f, err := findBuildfile(flag.Arg(0))
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
if f == "" {
|
|
||||||
f, err := findBuildfile("build.json")
|
|
||||||
failOn(err)
|
|
||||||
bf = f
|
|
||||||
} else {
|
|
||||||
consumedArgs = 1
|
|
||||||
bf = f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
re := []*regexp.Regexp{regexp.MustCompile(".")}
|
|
||||||
if len(flag.Args()) > consumedArgs {
|
|
||||||
re = re[:0]
|
|
||||||
for _, r := range flag.Args()[consumedArgs:] {
|
|
||||||
rx, err := regexp.Compile(r)
|
|
||||||
failOn(err)
|
|
||||||
re = append(re, rx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
project(bf, re, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func findTools(toolprefix string) {
|
|
||||||
var err error
|
|
||||||
for k, v := range tools {
|
|
||||||
if x := os.Getenv(strings.ToUpper(k)); x != "" {
|
|
||||||
v = x
|
|
||||||
}
|
|
||||||
if toolprefix != "" && v != "sh" && !strings.Contains(v, toolprefix) {
|
|
||||||
v = toolprefix + v;
|
|
||||||
}
|
|
||||||
v, err = exec.LookPath(v)
|
|
||||||
failOn(err)
|
|
||||||
tools[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// disambiguate the buildfile argument
|
|
||||||
func findBuildfile(f string) (string, error) {
|
|
||||||
if strings.HasSuffix(f, ".json"){
|
|
||||||
if fi, err := os.Stat(f); err == nil && !fi.IsDir() {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("unable to find buildfile %s", f)
|
|
||||||
}
|
|
||||||
if strings.Contains(f, "/") {
|
|
||||||
return findBuildfile(path.Join(f, "build.json"))
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
@ -1,182 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"debug/elf"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
const kernconfTmpl = `
|
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include "../port/error.h"
|
|
||||||
#include "io.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
rdb(void)
|
|
||||||
{
|
|
||||||
splhi();
|
|
||||||
iprint("rdb...not installed\n");
|
|
||||||
for(;;);
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ range .Rootcodes }}
|
|
||||||
{{ . }}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ range .Config.Dev }}extern Dev {{ . }}devtab;
|
|
||||||
{{ end }}
|
|
||||||
Dev *devtab[] = {
|
|
||||||
{{ range .Config.Dev }}
|
|
||||||
&{{ . }}devtab,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
{{ range .Config.Link }}extern void {{ . }}link(void);
|
|
||||||
{{ end }}
|
|
||||||
void
|
|
||||||
links(void)
|
|
||||||
{
|
|
||||||
{{ range .Rootnames }}addbootfile("{{ . }}", ramfs_{{ . }}_code, ramfs_{{ . }}_len);
|
|
||||||
{{ end }}
|
|
||||||
{{ range .Config.Link }}{{ . }}link();
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "../ip/ip.h"
|
|
||||||
{{ range .Config.Ip }}extern void {{ . }}init(Fs*);
|
|
||||||
{{ end }}
|
|
||||||
void (*ipprotoinit[])(Fs*) = {
|
|
||||||
{{ range .Config.Ip }} {{ . }}init,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "../port/sd.h"
|
|
||||||
{{ range .Config.Sd }}extern SDifc {{ . }}ifc;
|
|
||||||
{{ end }}
|
|
||||||
SDifc* sdifc[] = {
|
|
||||||
{{ range .Config.Sd }} &{{ . }}ifc,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
{{ range .Config.Uart }}extern PhysUart {{ . }}physuart;
|
|
||||||
{{ end }}
|
|
||||||
PhysUart* physuart[] = {
|
|
||||||
{{ range .Config.Uart }} &{{ . }}physuart,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define Image IMAGE
|
|
||||||
#include <draw.h>
|
|
||||||
#include <memdraw.h>
|
|
||||||
#include <cursor.h>
|
|
||||||
#include "screen.h"
|
|
||||||
{{ range .Config.VGA }}extern VGAdev {{ . }}dev;
|
|
||||||
{{ end }}
|
|
||||||
VGAdev* vgadev[] = {
|
|
||||||
{{ range .Config.VGA }} &{{ . }}dev,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
{{ range .Config.VGA }}extern VGAcur {{ . }}cur;
|
|
||||||
{{ end }}
|
|
||||||
VGAcur* vgacur[] = {
|
|
||||||
{{ range .Config.VGA }} &{{ . }}cur,
|
|
||||||
{{ end }}
|
|
||||||
nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
{{ range .Config.Code }}{{ . }}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
char* conffile = "{{ .Path }}";
|
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
// These are the two big code generation functions.
|
|
||||||
|
|
||||||
// data2c takes the file at path and creates a C byte array containing it.
|
|
||||||
func data2c(name string, path string) string {
|
|
||||||
var out []byte
|
|
||||||
var in []byte
|
|
||||||
|
|
||||||
if elf, err := elf.Open(path); err == nil {
|
|
||||||
elf.Close()
|
|
||||||
cwd, err := os.Getwd()
|
|
||||||
tmpf, err := ioutil.TempFile(cwd, name)
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
run(nil, *shellhack, exec.Command(tools["strip"], "-o", tmpf.Name(), path))
|
|
||||||
|
|
||||||
in, err = ioutil.ReadAll(tmpf)
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
tmpf.Close()
|
|
||||||
os.Remove(tmpf.Name())
|
|
||||||
} else {
|
|
||||||
var file *os.File
|
|
||||||
var err error
|
|
||||||
|
|
||||||
file, err = os.Open(path)
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
in, err = ioutil.ReadAll(file)
|
|
||||||
failOn(err)
|
|
||||||
|
|
||||||
file.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
total := len(in)
|
|
||||||
|
|
||||||
out = []byte(fmt.Sprintf("static unsigned char ramfs_%s_code[] = {\n", name))
|
|
||||||
for len(in) > 0 {
|
|
||||||
for j := 0; j < 16 && len(in) > 0; j++ {
|
|
||||||
out = append(out, []byte(fmt.Sprintf("0x%02x, ", in[0]))...)
|
|
||||||
in = in[1:]
|
|
||||||
}
|
|
||||||
out = append(out, '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
out = append(out, []byte(fmt.Sprintf("0,\n};\nint ramfs_%s_len = %v;\n", name, total))...)
|
|
||||||
|
|
||||||
return string(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// confcode creates a kernel configuration header.
|
|
||||||
func confcode(path string, kern *kernel) []byte {
|
|
||||||
var rootcodes []string
|
|
||||||
var rootnames []string
|
|
||||||
for name, path := range kern.Ramfiles {
|
|
||||||
code := data2c(name, fromRoot(path))
|
|
||||||
rootcodes = append(rootcodes, code)
|
|
||||||
rootnames = append(rootnames, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
vars := struct {
|
|
||||||
Path string
|
|
||||||
Config kernconfig
|
|
||||||
Rootnames []string
|
|
||||||
Rootcodes []string
|
|
||||||
}{
|
|
||||||
path,
|
|
||||||
kern.Config,
|
|
||||||
rootnames,
|
|
||||||
rootcodes,
|
|
||||||
}
|
|
||||||
tmpl := template.Must(template.New("kernconf").Parse(kernconfTmpl))
|
|
||||||
codebuf := &bytes.Buffer{}
|
|
||||||
failOn(tmpl.Execute(codebuf, vars))
|
|
||||||
return codebuf.Bytes()
|
|
||||||
}
|
|
@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
BUILDFILE FORMAT
|
|
||||||
|
|
||||||
A buildfile is a json object containing build objects. By convention, it's
|
|
||||||
broken out onto multiple lines indented by tabs, and the keys are TitleCased.
|
|
||||||
|
|
||||||
The environment varibles JEHANNE and ARCH are guarenteed to be set for the
|
|
||||||
buildfile. PATH is modified so that "$JEHANNE/hacking" is included.
|
|
||||||
|
|
||||||
Any key that takes a path or array of paths as its value has absolute paths
|
|
||||||
re-rooted to the jehanne tree and variables in the string expanded once.
|
|
||||||
|
|
||||||
The shell commands in the "Pre" and "Post" steps must be in the subset of
|
|
||||||
syntax that's accepted by both POSIX sh and rc. Practically, this means
|
|
||||||
arguments with a "=" must be single-quoted, "test" must be called as
|
|
||||||
"test" (not "["), "if" statements may not have an "else" clause, "switch"
|
|
||||||
statements may not be used, "for" statements may only have one body command,
|
|
||||||
and redirection to a file descriptor cannont be used.
|
|
||||||
|
|
||||||
BUILD OBJECT
|
|
||||||
|
|
||||||
A build object has the following keys and types:
|
|
||||||
|
|
||||||
Projects []string
|
|
||||||
Pre []string
|
|
||||||
Post []string
|
|
||||||
Cflags []string
|
|
||||||
Oflags []string
|
|
||||||
Include []string
|
|
||||||
SourceFiles []string
|
|
||||||
ObjectFiles []string
|
|
||||||
Libs []string
|
|
||||||
Env []string
|
|
||||||
SourceFilesCmd []string
|
|
||||||
Program string
|
|
||||||
Library string
|
|
||||||
Install string
|
|
||||||
Kernel kernel
|
|
||||||
|
|
||||||
These are the steps taken, in order:
|
|
||||||
|
|
||||||
Env
|
|
||||||
Include
|
|
||||||
Projects
|
|
||||||
Pre
|
|
||||||
Kernel
|
|
||||||
[compile] SourceFiles SourceFilesCmd Cflags Program
|
|
||||||
[link] ObjectFiles Libs Oflags Library
|
|
||||||
Install
|
|
||||||
Post
|
|
||||||
|
|
||||||
"[compile]" and "[link]" are steps synthesized from the specified keys.
|
|
||||||
|
|
||||||
The meaning of the keys is as follows:
|
|
||||||
|
|
||||||
"Env" is an array of environment variables to be put in the environment of
|
|
||||||
every command run in a build. They are expanded once and only available for
|
|
||||||
use in other steps.
|
|
||||||
|
|
||||||
"Include" is an array of buildfiles to "merge" into the current one. This
|
|
||||||
is done before other projects are built.
|
|
||||||
|
|
||||||
"Projects" is an array of buildfiles to build in their entirety before
|
|
||||||
starting the current build.
|
|
||||||
|
|
||||||
"Pre" is an array of commands to run before starting the build.
|
|
||||||
|
|
||||||
"Kernel" is a kernel build object. See the kernel object section.
|
|
||||||
|
|
||||||
"Cflags" is an array of flags to pass to the C compiler. They are in addition
|
|
||||||
to the standard flags of
|
|
||||||
|
|
||||||
-std=c11 -c -I /$ARCH/include -I /sys/include -I .
|
|
||||||
|
|
||||||
The standard include paths are re-rooted to the jehanne tree if not on a jehanne
|
|
||||||
system.
|
|
||||||
|
|
||||||
"SourceFilesCmd" is an array of C files where each one should result in an
|
|
||||||
executable. If this key is provided, "SourceFiles" and "Program" are ignored.
|
|
||||||
|
|
||||||
"SourceFiles" is an array of C files that will ultimately produce a single
|
|
||||||
binary or library, named by "Program" or "Library" respectively.
|
|
||||||
|
|
||||||
"Program" is the name of the final executable for the files specified by
|
|
||||||
"SourceFiles".
|
|
||||||
|
|
||||||
"Oflags" is an array of flags to pass to the linker. They are in addition
|
|
||||||
to the standard flags of
|
|
||||||
|
|
||||||
-o $program $objfiles -L /$ARCH/lib $libs
|
|
||||||
|
|
||||||
The lib path is re-rooted to the jehanne tree if not on a jehanne system.
|
|
||||||
|
|
||||||
"ObjectFiles" is an array of strings specifying object files to be linked
|
|
||||||
into the final program specified by "Program". Any object files produced
|
|
||||||
by the preceeding "[compile]" step are automatically added to this before
|
|
||||||
beginning the "[link]" step.
|
|
||||||
|
|
||||||
"Libs" is a an array of library arguments to pass to the linker.
|
|
||||||
|
|
||||||
"Library" is the name of the archive resulting from bundling "SourceFiles"
|
|
||||||
into a library. The resulting archive has 'ranlib' run on it automatically.
|
|
||||||
|
|
||||||
"Install" is a directory where the result of the "[link]" step is moved
|
|
||||||
to. If it does not exist, it is created.
|
|
||||||
|
|
||||||
"Post" is an array of commands to run last during the build.
|
|
||||||
|
|
||||||
KERNEL OBJECT
|
|
||||||
|
|
||||||
A build object has the following keys and types:
|
|
||||||
|
|
||||||
Systab string
|
|
||||||
Ramfiles map[string]string
|
|
||||||
Config {
|
|
||||||
Code []string
|
|
||||||
Dev []string
|
|
||||||
Ip []string
|
|
||||||
Link []string
|
|
||||||
Sd []string
|
|
||||||
Uart []string
|
|
||||||
VGA []string
|
|
||||||
}
|
|
||||||
|
|
||||||
"Systab" is the header that defines the syscall table.
|
|
||||||
|
|
||||||
"Ramfiles" is an object of name, path pairs of binaries at "path" that will
|
|
||||||
be baked into the kernel and available at a binary named "name".
|
|
||||||
|
|
||||||
"Config" is an object used to generate the kernel configuration source. "Dev",
|
|
||||||
"Ip", "Sd", "Uart", "Link", and "VGA" control which drivers of the various
|
|
||||||
types are included. "Code" is lines of arbitrary C code.
|
|
||||||
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var helptext = `
|
|
||||||
The buildfile is looked for at these positions, in this order:
|
|
||||||
|
|
||||||
./$arg
|
|
||||||
./$arg/build.json
|
|
||||||
/sys/src/$arg.json
|
|
||||||
/sys/src/$arg/build.json
|
|
||||||
|
|
||||||
If the buildfile argument is not provided, it defaults to "build.json".
|
|
||||||
|
|
||||||
After the buildfile, a number of regexps specifying targets may be provided.
|
|
||||||
If a target matches any supplied regexp, it is acted on. These regexps only
|
|
||||||
apply to the top-level buildfile.
|
|
||||||
|
|
||||||
BUILDFILE
|
|
||||||
|
|
||||||
See the build godoc for more information about the buildfile format.
|
|
||||||
|
|
||||||
ENVIRONMENT
|
|
||||||
|
|
||||||
ARCH is needed. Current acceptable vaules are: amd64
|
|
||||||
|
|
||||||
JEHANNE may be supplied to point at a jehanne tree.
|
|
||||||
The default on Jehanne is "/".
|
|
||||||
The default on Linux and OSX is to attempt to find the top level of a git
|
|
||||||
repository.
|
|
||||||
`
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.Usage = func() {
|
|
||||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
|
||||||
fmt.Fprintf(os.Stderr, " %s [options] [buildfile] [target...]\n\n", os.Args[0])
|
|
||||||
flag.PrintDefaults()
|
|
||||||
fmt.Fprintln(os.Stderr, helptext)
|
|
||||||
fmt.Fprintln(os.Stderr, "Tools to be used with current settings:")
|
|
||||||
fmt.Fprintf(os.Stderr, " prefix ($TOOLPREFIX): %q\n", os.Getenv("TOOLPREFIX"))
|
|
||||||
for k, v := range tools {
|
|
||||||
fmt.Fprintf(os.Stderr, " %s ($%s): %s\n", k, strings.ToUpper(k), v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
// +build !jehanne
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
jehanne = os.Getenv("JEHANNE")
|
|
||||||
if jehanne != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// git is purely optional, for lazy people.
|
|
||||||
out, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
|
|
||||||
if err == nil {
|
|
||||||
jehanne = strings.TrimSpace(string(out))
|
|
||||||
hackingAt := strings.LastIndex("/hacking", jehanne)
|
|
||||||
if(hackingAt >= 0){
|
|
||||||
jehanne = jehanne[0:hackingAt]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if jehanne == "" {
|
|
||||||
log.Fatal("Set the JEHANNE environment variable or run from a git checkout.")
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Setenv("PATH", strings.Join([]string{fromRoot("/hacking"), os.Getenv("PATH")}, string(os.PathListSeparator)))
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
// +build jehanne
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
jehanne = os.Getenv("JEHANNE")
|
|
||||||
if jehanne != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
jehanne = "/"
|
|
||||||
os.Setenv("path", strings.Join([]string{fromRoot("/util"), os.Getenv("path")}, string(os.PathListSeparator)))
|
|
||||||
}
|
|
@ -1,155 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var config = struct {
|
|
||||||
Jehanne string
|
|
||||||
Args []string
|
|
||||||
Except map[string]bool
|
|
||||||
CmdName string
|
|
||||||
FullPath string
|
|
||||||
Src string
|
|
||||||
Uroot string
|
|
||||||
Cwd string
|
|
||||||
Bbsh string
|
|
||||||
|
|
||||||
Goroot string
|
|
||||||
Gosrcroot string
|
|
||||||
Arch string
|
|
||||||
Goos string
|
|
||||||
Gopath string
|
|
||||||
TempDir string
|
|
||||||
Go string
|
|
||||||
Debug bool
|
|
||||||
Fail bool
|
|
||||||
}{
|
|
||||||
Jehanne: os.Getenv("JEHANNE"),
|
|
||||||
Except: map[string]bool{"sysconf.json": true},
|
|
||||||
}
|
|
||||||
|
|
||||||
type fixup func(string, map[string]interface{})
|
|
||||||
|
|
||||||
func cflags(n string, jsmap map[string]interface{}) {
|
|
||||||
if _, ok := jsmap["Cflags"]; ok {
|
|
||||||
log.Printf("Deleting Cflags from %v", n)
|
|
||||||
delete(jsmap, "Cflags")
|
|
||||||
// TODO: once we have another ARCH, use it.
|
|
||||||
a := []string{"/arch/amd64/include/cflags.json"}
|
|
||||||
switch tval := jsmap["Include"].(type) {
|
|
||||||
case []interface{}:
|
|
||||||
for _, v := range tval {
|
|
||||||
a = append(a, v.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsmap["Include"] = a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeempty(n string, jsmap map[string]interface{}) {
|
|
||||||
for key, val := range jsmap {
|
|
||||||
switch tval := val.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
log.Printf("%s: tval %s", n, tval)
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkname(n string, jsmap map[string]interface{}) {
|
|
||||||
if _, ok := jsmap["Name"]; !ok {
|
|
||||||
log.Print("File %v has no \"Name\" key", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func one(n string, f ...fixup) error {
|
|
||||||
buf, err := ioutil.ReadFile(n)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsmap map[string]interface{}
|
|
||||||
if err := json.Unmarshal(buf, &jsmap); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if config.Debug {
|
|
||||||
log.Printf("%v: %v", n, jsmap)
|
|
||||||
}
|
|
||||||
|
|
||||||
mapname := jsmap["Name"].(string)
|
|
||||||
delete(jsmap, "Name")
|
|
||||||
var nmap = make(map[string]map[string]interface{})
|
|
||||||
nmap[mapname] = jsmap
|
|
||||||
buf, err = json.MarshalIndent(nmap, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buf = append(buf, '\n')
|
|
||||||
|
|
||||||
if config.Debug {
|
|
||||||
os.Stdout.Write(buf)
|
|
||||||
} else {
|
|
||||||
ioutil.WriteFile(n, buf, 0666)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if config.Jehanne == "" {
|
|
||||||
log.Fatalf("Please set $JEHANNE")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(config.Args) == 0 {
|
|
||||||
config.Args = []string{config.Jehanne}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
flag.BoolVar(&config.Debug, "d", true, "Enable debug prints")
|
|
||||||
flag.Parse()
|
|
||||||
config.Args = flag.Args()
|
|
||||||
for _, n := range config.Args {
|
|
||||||
err = filepath.Walk(n, func(name string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
n := fi.Name()
|
|
||||||
if len(n) < 5 || n[len(n)-5:] != ".json" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if config.Except[fi.Name()] {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
todo := []fixup{removeempty, checkname}
|
|
||||||
log.Printf("process %s", name)
|
|
||||||
err = one(name, todo...)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s: %s\n", name, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("%v", err)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
a := flag.Args()
|
|
||||||
if len(a) != 2 {
|
|
||||||
fmt.Fprintf(os.Stderr, "[%v]usage: data2s name input-file (writes to stdout)\n", a)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
n := a[0]
|
|
||||||
i := a[1]
|
|
||||||
in, err := ioutil.ReadFile(i)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
total := len(in)
|
|
||||||
|
|
||||||
fmt.Printf("unsigned char %vcode[] = {\n", n)
|
|
||||||
for len(in) > 0 {
|
|
||||||
for j := 0; j < 16 && len(in) > 0; j++ {
|
|
||||||
fmt.Printf("0x%02x, ", in[0])
|
|
||||||
in = in[1:]
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("0,\n};\nint %vlen = %v;\n", n, total)
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"debug/elf"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
var dry = flag.Bool("dryrun", true, "don't really do it")
|
|
||||||
|
|
||||||
func gencode(w io.Writer, n, t string, m []byte, start, end uint64) {
|
|
||||||
fmt.Fprintf(os.Stderr, "Write %v %v start %v end %v\n", n, t, start, end)
|
|
||||||
fmt.Fprintf(w, "int %v_%v_start = %v;\n", n, t, start)
|
|
||||||
fmt.Fprintf(w, "int %v_%v_end = %v;\n", n, t, end)
|
|
||||||
fmt.Fprintf(w, "int %v_%v_len = %v;\n", n, t, end-start)
|
|
||||||
fmt.Fprintf(w, "uint8_t %v_%v_out[] = {\n", n, t)
|
|
||||||
for i := uint64(start); i < end; i += 16 {
|
|
||||||
for j := uint64(0); i+j < end && j < 16; j++ {
|
|
||||||
fmt.Fprintf(w, "0x%02x, ", m[j+i])
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "\n")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "};\n")
|
|
||||||
}
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
a := flag.Args()
|
|
||||||
for _, n := range a {
|
|
||||||
f, err := elf.Open(n)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v %v\n", n, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var dataend, codeend, end uint64
|
|
||||||
var datastart, codestart, start uint64
|
|
||||||
datastart, codestart, start = math.MaxUint64, math.MaxUint64, math.MaxUint64
|
|
||||||
mem := []byte{}
|
|
||||||
for _, v := range f.Progs {
|
|
||||||
if v.Type != elf.PT_LOAD {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "processing %v\n", v)
|
|
||||||
// MUST alignt to 2M page boundary.
|
|
||||||
// then MUST allocate a []byte that
|
|
||||||
// is the right size. And MUST
|
|
||||||
// see if by some off chance it
|
|
||||||
// joins to a pre-existing segment.
|
|
||||||
// It's easier than it seems. We produce ONE text
|
|
||||||
// array and ONE data array. So it's a matter of creating
|
|
||||||
// a virtual memory space with an assumed starting point of
|
|
||||||
// 0x200000, and filling it. We just grow that as needed.
|
|
||||||
|
|
||||||
curstart := v.Vaddr & ^uint64(0xfff) // 0x1fffff)
|
|
||||||
curend := v.Vaddr + v.Memsz
|
|
||||||
fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
|
|
||||||
if curend > end {
|
|
||||||
nmem := make([]byte, curend)
|
|
||||||
copy(nmem, mem)
|
|
||||||
mem = nmem
|
|
||||||
}
|
|
||||||
if curstart < start {
|
|
||||||
start = curstart
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Flags&elf.PF_X == elf.PF_X {
|
|
||||||
if curstart < codestart {
|
|
||||||
codestart = curstart
|
|
||||||
}
|
|
||||||
if curend > codeend {
|
|
||||||
codeend = curend
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "code s %v e %v\n", codestart, codeend)
|
|
||||||
} else {
|
|
||||||
if curstart < datastart {
|
|
||||||
datastart = curstart
|
|
||||||
}
|
|
||||||
if curend > dataend {
|
|
||||||
dataend = curend
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "data s %v e %v\n", datastart, dataend)
|
|
||||||
}
|
|
||||||
for i := uint64(0); i < v.Filesz; i++ {
|
|
||||||
if amt, err := v.ReadAt(mem[v.Vaddr+i:], int64(i)); err != nil && err != io.EOF {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v: %v\n", amt, err)
|
|
||||||
os.Exit(1)
|
|
||||||
} else if amt == 0 {
|
|
||||||
if i < v.Filesz {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v: Short read: %v of %v\n", v, i, v.Filesz)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
i = i + uint64(amt)
|
|
||||||
fmt.Fprintf(os.Stderr, "i now %v\n", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "Processed %v\n", v)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "gencode\n")
|
|
||||||
// Gen code to stdout. For each file, create an array, a start, and an end variable.
|
|
||||||
w := bufio.NewWriter(os.Stdout)
|
|
||||||
_, file := path.Split(n)
|
|
||||||
gencode(w, file, "code", mem, codestart, codeend)
|
|
||||||
gencode(w, file, "data", mem, datastart, dataend)
|
|
||||||
w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,197 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"compress/bzip2"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
dirPermissions = 0755
|
|
||||||
)
|
|
||||||
|
|
||||||
type Fetch struct {
|
|
||||||
Upstream string
|
|
||||||
Digest map[string]string
|
|
||||||
Compress string
|
|
||||||
RemovePrefix bool
|
|
||||||
Exclude []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
j, err := ioutil.ReadFile("fetch.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fetches := make(map[string]Fetch)
|
|
||||||
if err := json.Unmarshal(j, &fetches); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, f := range(fetches) {
|
|
||||||
if _, err := os.Stat(name); err == nil {
|
|
||||||
log.Printf("Fetch: skip %v (already present)", name)
|
|
||||||
} else {
|
|
||||||
log.Printf("Fetch: %v from %v", name, f.Upstream)
|
|
||||||
if err := do(&f, name); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func do(f *Fetch, name string) error {
|
|
||||||
fname := fetch(f)
|
|
||||||
s, err := os.Open(fname)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer os.Remove(fname)
|
|
||||||
|
|
||||||
os.MkdirAll(name, dirPermissions)
|
|
||||||
|
|
||||||
var unZ io.Reader
|
|
||||||
switch f.Compress {
|
|
||||||
case "gzip":
|
|
||||||
unZ, err = gzip.NewReader(s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "bzip2":
|
|
||||||
unZ = bzip2.NewReader(s)
|
|
||||||
default:
|
|
||||||
unZ = s
|
|
||||||
}
|
|
||||||
|
|
||||||
ar := tar.NewReader(unZ)
|
|
||||||
h, err := ar.Next()
|
|
||||||
untar:
|
|
||||||
for ; err == nil; h, err = ar.Next() {
|
|
||||||
n := h.Name
|
|
||||||
if f.RemovePrefix {
|
|
||||||
n = strings.SplitN(n, "/", 2)[1]
|
|
||||||
}
|
|
||||||
for _, ex := range f.Exclude {
|
|
||||||
if strings.HasPrefix(n, ex) {
|
|
||||||
continue untar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n = path.Join(name, n)
|
|
||||||
if h.FileInfo().IsDir() {
|
|
||||||
os.MkdirAll(n, dirPermissions)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
os.MkdirAll(path.Dir(n), dirPermissions)
|
|
||||||
out, err := os.Create(n)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := io.Copy(out, ar); n != h.Size || err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Close()
|
|
||||||
if err := os.Chmod(n, h.FileInfo().Mode()); err != nil {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type match struct {
|
|
||||||
hash.Hash
|
|
||||||
Good []byte
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m match) OK() bool {
|
|
||||||
return bytes.Equal(m.Good, m.Hash.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetch(v *Fetch) string {
|
|
||||||
if len(v.Digest) == 0 {
|
|
||||||
log.Fatal("no checksums specifed")
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "cmdVendor")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", v.Upstream, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
DisableCompression: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
var digests []match
|
|
||||||
for k, v := range v.Digest {
|
|
||||||
g, err := hex.DecodeString(v)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
switch k {
|
|
||||||
case "sha224":
|
|
||||||
digests = append(digests, match{sha256.New224(), g, k})
|
|
||||||
case "sha256":
|
|
||||||
digests = append(digests, match{sha256.New(), g, k})
|
|
||||||
case "sha384":
|
|
||||||
digests = append(digests, match{sha512.New384(), g, k})
|
|
||||||
case "sha512":
|
|
||||||
digests = append(digests, match{sha512.New(), g, k})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ws := make([]io.Writer, len(digests))
|
|
||||||
for i := range digests {
|
|
||||||
ws[i] = digests[i]
|
|
||||||
}
|
|
||||||
w := io.MultiWriter(ws...)
|
|
||||||
|
|
||||||
if _, err := io.Copy(f, io.TeeReader(res.Body, w)); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, h := range digests {
|
|
||||||
if !h.OK() {
|
|
||||||
log.Fatalf("mismatched %q hash\n\tWanted %x\n\tGot %x\n", h.Name, h.Good, h.Hash.Sum(nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return f.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(exe string, arg ...string) error {
|
|
||||||
cmd := exec.Command(exe, arg...)
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if len(os.Args) < 2 {
|
|
||||||
fmt.Printf("usage: jsonpretty input.json [output.json]\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(os.Args[1])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsmap map[string]interface{}
|
|
||||||
if err := json.Unmarshal(buf, &jsmap); err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, val := range jsmap {
|
|
||||||
switch tval := val.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err = json.MarshalIndent(jsmap, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
buf = append(buf, '\n')
|
|
||||||
|
|
||||||
if len(os.Args) == 3 {
|
|
||||||
ioutil.WriteFile(os.Args[2], buf, 0666)
|
|
||||||
} else {
|
|
||||||
os.Stdout.Write(buf)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"debug/elf"
|
|
||||||
"encoding/binary"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
const LRES = 3
|
|
||||||
|
|
||||||
var kernel = flag.String("k", "9k", "kernel name")
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
n := flag.Args()[0]
|
|
||||||
d, err := os.Open(n)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
f, err := elf.Open(*kernel)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var codeend uint64
|
|
||||||
var codestart uint64 = math.MaxUint64
|
|
||||||
|
|
||||||
for _, v := range f.Progs {
|
|
||||||
if v.Type != elf.PT_LOAD {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "processing %v\n", v)
|
|
||||||
// MUST alignt to 2M page boundary.
|
|
||||||
// then MUST allocate a []byte that
|
|
||||||
// is the right size. And MUST
|
|
||||||
// see if by some off chance it
|
|
||||||
// joins to a pre-existing segment.
|
|
||||||
// It's easier than it seems. We produce ONE text
|
|
||||||
// array and ONE data array. So it's a matter of creating
|
|
||||||
// a virtual memory space with an assumed starting point of
|
|
||||||
// 0x200000, and filling it. We just grow that as needed.
|
|
||||||
|
|
||||||
curstart := v.Vaddr
|
|
||||||
curend := v.Vaddr + v.Memsz
|
|
||||||
// magic numbers, BAH!
|
|
||||||
if curstart < uint64(0xffffffff00000000) {
|
|
||||||
curstart += 0xfffffffff0000000
|
|
||||||
curend += 0xfffffffff0000000
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "s %x e %x\n", curstart, curend)
|
|
||||||
if v.Flags&elf.PF_X == elf.PF_X {
|
|
||||||
if curstart < codestart {
|
|
||||||
codestart = curstart
|
|
||||||
}
|
|
||||||
if curend > codeend {
|
|
||||||
codeend = curend
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "code s %x e %x\n", codestart, codeend)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "code s %x e %x\n", codestart, codeend)
|
|
||||||
s, err := f.Symbols()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
// maybe we should stop doing LRES ...
|
|
||||||
symname := make([]string, codeend-codestart)
|
|
||||||
for i := range symname {
|
|
||||||
symname[i] = fmt.Sprintf("[0x%x]", codestart+uint64(i))
|
|
||||||
}
|
|
||||||
for _, v := range s {
|
|
||||||
vstart := v.Value
|
|
||||||
vend := v.Value + v.Size
|
|
||||||
if v.Value > codeend {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if v.Value+v.Size < codestart {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if vstart < codestart {
|
|
||||||
v.Value = codestart
|
|
||||||
}
|
|
||||||
if vend > codeend {
|
|
||||||
vend = codeend
|
|
||||||
}
|
|
||||||
for i := vstart; i < vend; i++ {
|
|
||||||
symname[i-codestart] = v.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
symname[0] = "Total ms"
|
|
||||||
symname[1<<LRES] = "Unknown"
|
|
||||||
// now dump the info ...
|
|
||||||
count := uint32(0)
|
|
||||||
pc := codestart
|
|
||||||
for {
|
|
||||||
if err := binary.Read(d, binary.BigEndian, &count); err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if count > 0 {
|
|
||||||
fmt.Printf("%s %d\n", symname[pc-codestart], count)
|
|
||||||
}
|
|
||||||
pc += (1 << LRES)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,385 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Jehanne.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
||||||
*
|
|
||||||
* Jehanne 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, version 3 of the License.
|
|
||||||
*
|
|
||||||
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SyscallConf struct {
|
|
||||||
Ret []string
|
|
||||||
Args []string
|
|
||||||
Name string
|
|
||||||
Id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Sysconf struct {
|
|
||||||
Syscalls []SyscallConf
|
|
||||||
}
|
|
||||||
|
|
||||||
func usage(msg string) {
|
|
||||||
fmt.Fprint(os.Stderr, msg)
|
|
||||||
fmt.Fprint(os.Stderr, "Usage: ksyscalls path/to/sysconf.json\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyscallWrapper struct {
|
|
||||||
Id uint32
|
|
||||||
Name string
|
|
||||||
Vars []string
|
|
||||||
CommonCode string
|
|
||||||
ExecCode string
|
|
||||||
EntryPrint string
|
|
||||||
ExitPrint string
|
|
||||||
SysRetField string
|
|
||||||
DefaultRet string
|
|
||||||
}
|
|
||||||
|
|
||||||
type KernelCode struct {
|
|
||||||
Externs []string
|
|
||||||
Wrappers []SyscallWrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func uregArg(index int) string{
|
|
||||||
switch(index){
|
|
||||||
case 0:
|
|
||||||
return "di";
|
|
||||||
case 1:
|
|
||||||
return "si";
|
|
||||||
case 2:
|
|
||||||
return "dx";
|
|
||||||
case 3:
|
|
||||||
return "r10";
|
|
||||||
case 4:
|
|
||||||
return "r8";
|
|
||||||
case 5:
|
|
||||||
return "r9";
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func sysret(t string) string {
|
|
||||||
switch(t){
|
|
||||||
case "int", "int32_t":
|
|
||||||
return "i"
|
|
||||||
case "long", "int64_t":
|
|
||||||
return "vl"
|
|
||||||
case "uintptr_t", "void":
|
|
||||||
return "p"
|
|
||||||
case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*":
|
|
||||||
return "v"
|
|
||||||
}
|
|
||||||
return " [?? " + t + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatArg(i int, t string) string{
|
|
||||||
switch(t){
|
|
||||||
case "int", "int32_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%d\", a%d);\n", i)
|
|
||||||
case "unsigned int", "uint32_t":
|
|
||||||
/* unsigned int is reserved for flags */
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#ux\", a%d);\n", i)
|
|
||||||
case "long", "int64_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%lld\", a%d);\n", i)
|
|
||||||
case "unsigned long", "uint64_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#lud\", a%d);\n", i)
|
|
||||||
case "void*", "uint8_t*", "const void*", "const uint8_t*":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p\", a%d);\n", i)
|
|
||||||
case "int32_t*", "int*", "const int32_t*", "const int*":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p(%%d)\", a%d, a%d);\n", i, i)
|
|
||||||
case "const char*", "char*":
|
|
||||||
return fmt.Sprintf("\tfmtuserstring(fmt, a%d);\n", i)
|
|
||||||
case "const char**", "char**":
|
|
||||||
return fmt.Sprintf("\tfmtuserstringlist(fmt, a%d);\n", i);
|
|
||||||
}
|
|
||||||
return " [?? " + t + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatRet(t string) string{
|
|
||||||
switch(t){
|
|
||||||
case "int", "int32_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%d\", ret->%s);\n", sysret(t))
|
|
||||||
case "unsigned int", "uint32_t":
|
|
||||||
/* unsigned int is reserved for flags */
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#ux\", ret->%s);\n", sysret(t))
|
|
||||||
case "long", "int64_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%lld\", ret->%s);\n", sysret(t))
|
|
||||||
case "unsigned long", "uint64_t", "void":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#llud\", ret->%s);\n", sysret(t))
|
|
||||||
case "void*", "uintptr_t", "const void*", "const uintptr_t":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p\", ret->%s);\n", sysret(t))
|
|
||||||
case "int32_t*", "int*", "const int32_t*", "const int*":
|
|
||||||
return fmt.Sprintf("\tjehanne_fmtprint(fmt, \" %%#p(%%d)\", ret->%s, *ret->%s);\n", sysret(t), sysret(t))
|
|
||||||
}
|
|
||||||
return " [?? " + t + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateKernelCode(calls []SyscallConf){
|
|
||||||
code := new(KernelCode)
|
|
||||||
|
|
||||||
for _, call := range(calls) {
|
|
||||||
/* extern definitions */
|
|
||||||
ext := "extern " + call.Ret[0] + " sys" + call.Name + "("
|
|
||||||
if len(call.Args) == 0 {
|
|
||||||
ext += "void";
|
|
||||||
} else {
|
|
||||||
for i, a := range(call.Args){
|
|
||||||
if i > 0 {
|
|
||||||
ext += ", "
|
|
||||||
}
|
|
||||||
ext += fmt.Sprintf("%s", a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ext += ");\n"
|
|
||||||
|
|
||||||
wcall := new(SyscallWrapper)
|
|
||||||
wcall.Id = call.Id
|
|
||||||
wcall.Name = call.Name
|
|
||||||
wcall.SysRetField = sysret(call.Ret[0])
|
|
||||||
wcall.DefaultRet = fmt.Sprintf("ret.%s = (%s)-1;", wcall.SysRetField, call.Ret[0])
|
|
||||||
|
|
||||||
for i, a := range(call.Args){
|
|
||||||
wcall.Vars = append(wcall.Vars, fmt.Sprintf("%s a%v;", a, i))
|
|
||||||
wcall.CommonCode += fmt.Sprintf("\ta%v = (%s)ureg->%s;\n", i, a, uregArg(i))
|
|
||||||
}
|
|
||||||
wcall.ExecCode += "\tret->" + wcall.SysRetField + " = sys" + call.Name + "("
|
|
||||||
for i, _ := range(call.Args){
|
|
||||||
if i > 0 {
|
|
||||||
wcall.ExecCode += ", "
|
|
||||||
}
|
|
||||||
wcall.ExecCode += fmt.Sprintf("a%v", i)
|
|
||||||
}
|
|
||||||
wcall.ExecCode += ");"
|
|
||||||
|
|
||||||
if call.Name == "pwrite"{
|
|
||||||
wcall.EntryPrint += formatArg(0, call.Args[0])
|
|
||||||
wcall.EntryPrint += "\tfmtrwdata(fmt, (char*)a1, MIN(a2, 64));\n"
|
|
||||||
wcall.EntryPrint += formatArg(2, call.Args[2])
|
|
||||||
wcall.EntryPrint += formatArg(3, call.Args[3])
|
|
||||||
} else {
|
|
||||||
for i, a := range(call.Args){
|
|
||||||
wcall.EntryPrint += formatArg(i, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wcall.ExitPrint += formatRet(call.Ret[0])
|
|
||||||
if call.Name == "pread"{
|
|
||||||
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(1), uregArg(2))
|
|
||||||
} else if call.Name == "fd2path"{
|
|
||||||
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(1), uregArg(2))
|
|
||||||
} else if call.Name == "await"{
|
|
||||||
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(0), uregArg(1))
|
|
||||||
} else if call.Name == "errstr"{
|
|
||||||
wcall.ExitPrint += fmt.Sprintf("\tfmtrwdata(fmt, (char*)ureg->%s, MIN(ureg->%s, 64));\n", uregArg(0), uregArg(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
code.Wrappers = append(code.Wrappers, *wcall)
|
|
||||||
code.Externs = append(code.Externs, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, err := template.New("systab.c").Parse(`/*
|
|
||||||
* This file is part of Jehanne.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
|
|
||||||
*
|
|
||||||
* Jehanne 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, version 3 of the License.
|
|
||||||
*
|
|
||||||
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/* automatically generated by ksyscalls */
|
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include "../port/error.h"
|
|
||||||
#include "ureg.h"
|
|
||||||
|
|
||||||
extern void fmtrwdata(Fmt* f, char* a, int n);
|
|
||||||
extern void fmtuserstring(Fmt* f, const char* a);
|
|
||||||
extern void fmtuserstringlist(Fmt* f, const char** argv);
|
|
||||||
|
|
||||||
{{ range .Externs }}{{.}}{{ end }}
|
|
||||||
{{ range .Wrappers }}
|
|
||||||
static void
|
|
||||||
wrap_{{ .Name }}(ScRet* ret, Ureg* ureg)
|
|
||||||
{
|
|
||||||
{{ range .Vars }}{{.}}
|
|
||||||
{{ end }}
|
|
||||||
{{ .CommonCode }}
|
|
||||||
{{ .ExecCode }}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
int nsyscall = {{len .Wrappers}};
|
|
||||||
|
|
||||||
ScRet
|
|
||||||
default_syscall_ret(int syscall)
|
|
||||||
{
|
|
||||||
static ScRet zero;
|
|
||||||
ScRet ret = zero;
|
|
||||||
switch(syscall){
|
|
||||||
{{ range .Wrappers }}case {{ .Id }}:
|
|
||||||
{{ .DefaultRet }}
|
|
||||||
break;
|
|
||||||
{{ end }}
|
|
||||||
default:
|
|
||||||
ret.vl = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
syscall_name(int syscall)
|
|
||||||
{
|
|
||||||
switch(syscall){
|
|
||||||
{{ range .Wrappers }}case {{ .Id }}:
|
|
||||||
return "{{ .Name }}";
|
|
||||||
{{ end }}
|
|
||||||
default:
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dispatch_syscall(int syscall, Ureg* ureg, ScRet* ret)
|
|
||||||
{
|
|
||||||
switch(syscall){
|
|
||||||
{{ range .Wrappers }}case {{ .Id }}:
|
|
||||||
wrap_{{ .Name }}(ret, ureg);
|
|
||||||
break;
|
|
||||||
{{ end }}
|
|
||||||
default:
|
|
||||||
panic("dispatch_syscall: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ range .Wrappers }}
|
|
||||||
static void
|
|
||||||
enter_{{ .Name }}(Fmt* fmt, Ureg* ureg)
|
|
||||||
{
|
|
||||||
{{ range .Vars }}{{.}}
|
|
||||||
{{ end }}
|
|
||||||
{{ .CommonCode }}
|
|
||||||
jehanne_fmtprint(fmt, "{{ .Name }} %#p >", ureg->ip);
|
|
||||||
if(up->notified)
|
|
||||||
jehanne_fmtprint(fmt, "!");
|
|
||||||
{{ .EntryPrint }}
|
|
||||||
jehanne_fmtprint(fmt, "\n");
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
char*
|
|
||||||
syscallfmt(int syscall, Ureg* ureg)
|
|
||||||
{
|
|
||||||
Fmt fmt;
|
|
||||||
jehanne_fmtstrinit(&fmt);
|
|
||||||
jehanne_fmtprint(&fmt, "%d %s ", up->pid, up->text);
|
|
||||||
|
|
||||||
switch(syscall){
|
|
||||||
{{ range .Wrappers }}case {{ .Id }}:
|
|
||||||
enter_{{ .Name }}(&fmt, ureg);
|
|
||||||
break;
|
|
||||||
{{ end }}
|
|
||||||
default:
|
|
||||||
panic("syscallfmt: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
return jehanne_fmtstrflush(&fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
{{ range .Wrappers }}
|
|
||||||
static void
|
|
||||||
exit_{{ .Name }}(Fmt* fmt, Ureg* ureg, ScRet* ret)
|
|
||||||
{
|
|
||||||
jehanne_fmtprint(fmt, "{{ .Name }} %#p <", ureg->ip);
|
|
||||||
if(up->notified)
|
|
||||||
jehanne_fmtprint(fmt, "!");
|
|
||||||
{{ .ExitPrint }}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
char*
|
|
||||||
sysretfmt(int syscall, Ureg* ureg, ScRet* ret, uint64_t start, uint64_t stop)
|
|
||||||
{
|
|
||||||
Fmt fmt;
|
|
||||||
jehanne_fmtstrinit(&fmt);
|
|
||||||
jehanne_fmtprint(&fmt, "%d %s ", up->pid, up->text);
|
|
||||||
|
|
||||||
switch(syscall){
|
|
||||||
{{ range .Wrappers }}case {{ .Id }}:
|
|
||||||
exit_{{ .Name }}(&fmt, ureg, ret);
|
|
||||||
break;
|
|
||||||
{{ end }}
|
|
||||||
default:
|
|
||||||
panic("sysretfmt: bad sys call number %d pc %#p\n", syscall, ureg->ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 > ret->vl){
|
|
||||||
jehanne_fmtprint(&fmt, " %s %#llud %#llud\n", up->syserrstr, start, stop-start);
|
|
||||||
} else {
|
|
||||||
jehanne_fmtprint(&fmt, " \"\" %#llud %#llud\n", start, stop-start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return jehanne_fmtstrflush(&fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(os.Stdout, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if flag.NArg() != 1 {
|
|
||||||
usage("no path to sysconf.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(flag.Arg(0))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sysconf Sysconf
|
|
||||||
err = json.Unmarshal(buf, &sysconf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
generateKernelCode(sysconf.Syscalls)
|
|
||||||
|
|
||||||
}
|
|
@ -1,325 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the UCB release of Plan 9. It is subject to the license
|
|
||||||
* terms in the LICENSE file found in the top-level directory of this
|
|
||||||
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
||||||
* part of the UCB release of Plan 9, including this file, may be copied,
|
|
||||||
* modified, propagated, or distributed except according to the terms contained
|
|
||||||
* in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Syscall struct {
|
|
||||||
Ret []string
|
|
||||||
Args []string
|
|
||||||
Name string
|
|
||||||
Id uint32
|
|
||||||
Define string
|
|
||||||
Sysname string
|
|
||||||
Libname string
|
|
||||||
Fudge string `json:"-"`
|
|
||||||
GoArgs []string `json:"-"`
|
|
||||||
Ret0 string `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Syserror struct {
|
|
||||||
Name string
|
|
||||||
String string
|
|
||||||
Id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bootmethods struct {
|
|
||||||
Name string
|
|
||||||
Config string
|
|
||||||
Connect string
|
|
||||||
Arg string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Sysconf struct {
|
|
||||||
Syscalls []Syscall
|
|
||||||
Syserrors []Syserror
|
|
||||||
Bootmethods []Bootmethods
|
|
||||||
}
|
|
||||||
|
|
||||||
var mode = flag.String("mode", "", "must be one of: sys.h, sysdecl.h, syscallfiles, systab.c, error.h, errstr.h, sys_jehanne.s, sysnum.go")
|
|
||||||
var outpath = flag.String("o", "", "path/to/output.c")
|
|
||||||
|
|
||||||
func usage(msg string) {
|
|
||||||
fmt.Fprint(os.Stderr, msg)
|
|
||||||
fmt.Fprint(os.Stderr, "Usage: mksys [-o outpath] -mode=MODE path/to/sysconf.json\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if flag.NArg() != 1 {
|
|
||||||
usage("no path to sysconf.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
outfile := os.Stdout
|
|
||||||
if *mode != "syscallfiles" && *outpath != "" {
|
|
||||||
of, err := os.Create(*outpath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
outfile = of
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(flag.Arg(0))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sysconf Sysconf
|
|
||||||
err = json.Unmarshal(buf, &sysconf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
syscalls := sysconf.Syscalls
|
|
||||||
syserrors := sysconf.Syserrors
|
|
||||||
bootmethods := sysconf.Bootmethods
|
|
||||||
for i := range syscalls {
|
|
||||||
if syscalls[i].Define == "" {
|
|
||||||
syscalls[i].Define = strings.ToUpper(syscalls[i].Name)
|
|
||||||
}
|
|
||||||
if syscalls[i].Sysname == "" {
|
|
||||||
syscalls[i].Sysname = "sys" + syscalls[i].Name
|
|
||||||
}
|
|
||||||
if syscalls[i].Libname == "" {
|
|
||||||
syscalls[i].Libname = syscalls[i].Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch *mode {
|
|
||||||
case "sys_jehanne.s":
|
|
||||||
if os.Getenv("ARCH") != "amd64" {
|
|
||||||
usage("ARCH unsupported or not set")
|
|
||||||
}
|
|
||||||
syscallargs := []string{"DI", "SI", "DX", "R10", "R8", "R9"}
|
|
||||||
//funcallregs := []string{ "DI", "SI", "DX", "CX", "R8", "R9" };
|
|
||||||
for i := range syscalls {
|
|
||||||
goargs := []string{}
|
|
||||||
fpoff := 0
|
|
||||||
for k := range syscalls[i].Args {
|
|
||||||
switch syscalls[i].Args[k] {
|
|
||||||
case "int32_t", "uint32_t":
|
|
||||||
goargs = append(goargs, fmt.Sprintf("MOVL arg%d+%d(FP), %s", k, fpoff, syscallargs[k]))
|
|
||||||
fpoff += 4
|
|
||||||
case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*", "int64_t":
|
|
||||||
fpoff = (fpoff + 7) & ^7
|
|
||||||
goargs = append(goargs, fmt.Sprintf("MOVQ arg%d+%d(FP), %s", k, fpoff, syscallargs[k]))
|
|
||||||
fpoff += 8
|
|
||||||
default:
|
|
||||||
log.Fatalf("unsupported arg %s in syscall: %v", syscalls[i].Args[k], syscalls[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
syscalls[i].GoArgs = goargs
|
|
||||||
switch syscalls[i].Ret[0] {
|
|
||||||
case "int32_t", "uint32_t":
|
|
||||||
syscalls[i].Ret0 = fmt.Sprintf("MOVL AX, ret+%d(FP)", fpoff)
|
|
||||||
fpoff += 4
|
|
||||||
case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*", "int64_t":
|
|
||||||
fpoff = (fpoff + 7) & ^7
|
|
||||||
syscalls[i].Ret0 = fmt.Sprintf("MOVQ AX, ret+%d(FP)", fpoff)
|
|
||||||
fpoff += 8
|
|
||||||
default:
|
|
||||||
log.Fatalf("unsupported Ret[0] in syscall: %v", syscalls[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmpl, err := template.New("sys_jehanne.s").Parse(`/* automatically generated by mksys */
|
|
||||||
/* System calls for AMD64, Jehanne */
|
|
||||||
#include "go_asm.h"
|
|
||||||
#include "go_tls.h"
|
|
||||||
#include "textflag.h"
|
|
||||||
{{ range . }}
|
|
||||||
TEXT runtime·{{ .Libname }}(SB),NOSPLIT,$0
|
|
||||||
{{ range .GoArgs }} {{ . }}
|
|
||||||
{{ end }} MOVQ ${{ .Id }}, AX
|
|
||||||
SYSCALL
|
|
||||||
{{ .Ret0 }}
|
|
||||||
RET
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tmpl.Execute(outfile, syscalls)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "syscallfiles":
|
|
||||||
if os.Getenv("ARCH") != "amd64" {
|
|
||||||
usage("ARCH unsupported or not set")
|
|
||||||
}
|
|
||||||
tmpl, err := template.New("syscall.s").Parse(`/* automatically generated by mksys */
|
|
||||||
.globl {{ .Libname }}
|
|
||||||
{{ .Libname }}:
|
|
||||||
movq %rcx, %r10 /* rcx gets smashed by systenter. Use r10.*/
|
|
||||||
movq ${{ .Id }},%rax /* Put the system call into rax, just like linux. */
|
|
||||||
syscall
|
|
||||||
ret
|
|
||||||
`)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range syscalls {
|
|
||||||
|
|
||||||
path := path.Join(*outpath, syscalls[i].Libname+".s")
|
|
||||||
file, err := os.Create(path)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tmpl.Execute(file, syscalls[i])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "sysnum.go":
|
|
||||||
tmpl, err := template.New("sysnum.go").Parse(`// automatically generated by mksys
|
|
||||||
package syscall
|
|
||||||
|
|
||||||
const(
|
|
||||||
{{ range . }} SYS_{{ .Define }} = {{ .Id }}
|
|
||||||
{{ end }}
|
|
||||||
)
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syscalls)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "sys.h":
|
|
||||||
tmpl, err := template.New("sys.h").Parse(`/* automatically generated by mksys */
|
|
||||||
{{ range . }}#define {{ .Define }} {{ .Id }}
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syscalls)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "sysdecl.h":
|
|
||||||
tmpl, err := template.New("sysdecl.h").Parse(`/* automatically generated by mksys */
|
|
||||||
{{ range . }}extern {{ .Ret0 }} {{ .Libname }}({{ range $i, $e := .Args }}{{ if $i }}, {{ end }}{{ $e }}{{ end }});
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syscalls)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "systab.c":
|
|
||||||
for i := range syscalls {
|
|
||||||
var fudge string
|
|
||||||
switch syscalls[i].Ret[0] {
|
|
||||||
case "int32_t":
|
|
||||||
fudge = "{ .i = -1 }"
|
|
||||||
case "int64_t":
|
|
||||||
fudge = "{ .vl = -1ll }"
|
|
||||||
case "void*", "char*":
|
|
||||||
fudge = "{ .v = (void*)-1ll }"
|
|
||||||
default:
|
|
||||||
log.Fatalf("unsupported Ret[0] in syscall: %v", syscalls[i])
|
|
||||||
}
|
|
||||||
if syscalls[i].Fudge == "" {
|
|
||||||
syscalls[i].Fudge = fudge
|
|
||||||
}
|
|
||||||
|
|
||||||
syscalls[i].Ret0 = syscalls[i].Ret[0]
|
|
||||||
}
|
|
||||||
tmpl, err := template.New("systab.c").Parse(`/* automatically generated by mksys */
|
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include <9syscall/sys.h>
|
|
||||||
|
|
||||||
{{ range . }}extern void {{ .Sysname }}(ScRet*, ScArg, ScArg, ScArg, ScArg, ScArg, ScArg);
|
|
||||||
{{ end }}
|
|
||||||
Systab systab[] = {
|
|
||||||
{{ range . }}[{{ .Define }}] { "{{ .Name }}", {{ .Sysname }}, {{ .Fudge }} },
|
|
||||||
{{ end }}
|
|
||||||
};
|
|
||||||
int nsyscall = nelem(systab);
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syscalls)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "error.h":
|
|
||||||
tmpl, err := template.New("error.h").Parse(`/* automatically generated by mksys */
|
|
||||||
{{ range . }}extern char {{ .Name }}[]; /* {{ .String }} */
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syserrors)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "errstr.h":
|
|
||||||
tmpl, err := template.New("errstr.h").Parse(`/* automatically generated by mksys */
|
|
||||||
{{ range . }}char {{ .Name }}[] = "{{ .String }}";
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, syserrors)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
case "bootamd64cpu.c":
|
|
||||||
tmpl, err := template.New("bootamd64cpu.c").Parse(`/* automatically generated by mksys */
|
|
||||||
#include <u.h>
|
|
||||||
#include <libc.h>
|
|
||||||
|
|
||||||
#include "../boot/boot.h"
|
|
||||||
|
|
||||||
Method method[] = {
|
|
||||||
{{ range . }}{ "{{.Name}}", {{.Config}}, {{.Connect}}, "{{.Arg}}", },
|
|
||||||
{{ end }}
|
|
||||||
{ nil },
|
|
||||||
};
|
|
||||||
|
|
||||||
int cpuflag = 1;
|
|
||||||
char* rootdir = "/root";
|
|
||||||
char* bootdisk = "#S/sdE0/";
|
|
||||||
extern void boot(int, char**);
|
|
||||||
|
|
||||||
void
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
boot(argc, argv);
|
|
||||||
}
|
|
||||||
int (*cfs)(int) = 0;
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(outfile, bootmethods)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
first word
|
|
||||||
high 8 bits is ee, which is an invalid address on amd64.
|
|
||||||
next 8 bits is protocol version
|
|
||||||
next 16 bits is unused, MBZ. Later, we can make it a packet type.
|
|
||||||
next 16 bits is core id
|
|
||||||
next 8 bits is unused
|
|
||||||
next 8 bits is # words following.
|
|
||||||
|
|
||||||
second word is time in ns. (soon to be tsc ticks)
|
|
||||||
|
|
||||||
Third and following words are PCs, there must be at least one of them.
|
|
||||||
*/
|
|
||||||
type sample struct {
|
|
||||||
Wordcount, _ uint8
|
|
||||||
Coreid uint16
|
|
||||||
_ uint16
|
|
||||||
Version, Marker uint8
|
|
||||||
Ns uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type backtrace struct {
|
|
||||||
Pcs []uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the docs lie. Perl expects Count to be zero. I only wasted a day figuring this out. */
|
|
||||||
type hdr struct {
|
|
||||||
Count, Slots, Format, Period, Padding uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type record struct {
|
|
||||||
Count, Size uint64
|
|
||||||
Pcs []uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type trailer struct {
|
|
||||||
Zero, One, Zeroh uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var s sample
|
|
||||||
|
|
||||||
r := io.Reader(os.Stdin)
|
|
||||||
w := io.Writer(os.Stdout)
|
|
||||||
|
|
||||||
records := make(map[string]uint64, 16384)
|
|
||||||
backtraces := make(map[string][]uint64, 1024)
|
|
||||||
|
|
||||||
/* ignore the documentation, it's wrong, first word must be zero.
|
|
||||||
* the perl code that figures word length depends on it.
|
|
||||||
*/
|
|
||||||
hdr := hdr{0, 3, 0, 10000, 0}
|
|
||||||
trailer := trailer{0, 1, 0}
|
|
||||||
start := uint64(0)
|
|
||||||
end := start
|
|
||||||
nsamples := end
|
|
||||||
for binary.Read(r, binary.LittleEndian, &s) == nil {
|
|
||||||
numpcs := int(s.Wordcount)
|
|
||||||
bt := make([]uint64, numpcs)
|
|
||||||
binary.Read(r, binary.LittleEndian, &bt)
|
|
||||||
//fmt.Printf("%v\n", bt)
|
|
||||||
record := ""
|
|
||||||
/* Fix the symbols. pprof was unhappy about the 0xfffffff.
|
|
||||||
* N.B. The fact that we have to mess with the bt values
|
|
||||||
* is the reason we did not write a stringer for bt.
|
|
||||||
*/
|
|
||||||
for i := range bt {
|
|
||||||
bt[i] = bt[i] & ((uint64(1) << 32) - 1)
|
|
||||||
record = record + fmt.Sprintf("0x%x ", bt[i])
|
|
||||||
}
|
|
||||||
records[record]++
|
|
||||||
backtraces[record] = bt
|
|
||||||
//fmt.Printf("%v %d %d %x %v record %v\n", s, s.Wordcount, s.Coreid, s.Ns, bt, record)
|
|
||||||
/* how sad, once we go to ticks this gets ugly. */
|
|
||||||
if start == 0 {
|
|
||||||
start = s.Ns
|
|
||||||
}
|
|
||||||
end = s.Ns
|
|
||||||
nsamples++
|
|
||||||
}
|
|
||||||
/* we'll need to fix this once we go to ticks. */
|
|
||||||
hdr.Period = (end - start) / nsamples
|
|
||||||
hdr.Count = uint64(0) // !@$@!#$!@#$len(records))
|
|
||||||
//fmt.Printf("start %v end %v nsamples %d period %d\n", start, end, nsamples, hdr.Period)
|
|
||||||
binary.Write(w, binary.LittleEndian, &hdr)
|
|
||||||
out := make([]uint64, 2)
|
|
||||||
/* note that the backtrace length varies. But we're good with that. */
|
|
||||||
for key, v := range records {
|
|
||||||
bt := backtraces[key]
|
|
||||||
out[0] = v
|
|
||||||
out[1] = uint64(len(bt))
|
|
||||||
dump := append(out, bt...)
|
|
||||||
//fmt.Printf("dump %v\n", dump)
|
|
||||||
binary.Write(w, binary.LittleEndian, &dump)
|
|
||||||
}
|
|
||||||
binary.Write(w, binary.LittleEndian, &trailer)
|
|
||||||
|
|
||||||
}
|
|
1
src/jehanne/cmd/preen/.gitignore
vendored
1
src/jehanne/cmd/preen/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
/preen
|
|
@ -1,157 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var config = struct {
|
|
||||||
Jehanne string
|
|
||||||
Args []string
|
|
||||||
Except map[string]bool
|
|
||||||
CmdName string
|
|
||||||
FullPath string
|
|
||||||
Src string
|
|
||||||
Uroot string
|
|
||||||
Cwd string
|
|
||||||
Bbsh string
|
|
||||||
|
|
||||||
Goroot string
|
|
||||||
Gosrcroot string
|
|
||||||
Arch string
|
|
||||||
Goos string
|
|
||||||
Gopath string
|
|
||||||
TempDir string
|
|
||||||
Go string
|
|
||||||
Debug bool
|
|
||||||
Fail bool
|
|
||||||
}{
|
|
||||||
Jehanne: os.Getenv("JEHANNE"),
|
|
||||||
Except: map[string]bool{"cflags.json": true, "9": true, "libauthcmd.json": true, "awk.json": true, "bzip2": true, "klibc.json": true, "kcmds.json": true, "klib.json": true, "kernel.json": true},
|
|
||||||
}
|
|
||||||
|
|
||||||
type fixup func(string, map[string]interface{})
|
|
||||||
|
|
||||||
func cflags(n string, jsmap map[string]interface{}) {
|
|
||||||
if _, ok := jsmap["Cflags"]; ok {
|
|
||||||
log.Printf("Deleting Cflags from %v", n)
|
|
||||||
delete(jsmap, "Cflags")
|
|
||||||
// TODO: once we have another ARCH, use it.
|
|
||||||
a := []string{"/arch/amd64/include/cflags.json"}
|
|
||||||
switch tval := jsmap["Include"].(type) {
|
|
||||||
case []interface{}:
|
|
||||||
for _, v := range tval {
|
|
||||||
a = append(a, v.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsmap["Include"] = a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeempty(n string, jsmap map[string]interface{}) {
|
|
||||||
for key, val := range jsmap {
|
|
||||||
switch tval := val.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
log.Printf("%s: tval %s", n, tval)
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
if len(tval) == 0 {
|
|
||||||
delete(jsmap, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkname(n string, jsmap map[string]interface{}) {
|
|
||||||
if _, ok := jsmap["Name"]; !ok {
|
|
||||||
log.Print("File %v has no \"Name\" key", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func one(n string, f ...fixup) error {
|
|
||||||
buf, err := ioutil.ReadFile(n)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsmap map[string]interface{}
|
|
||||||
if err := json.Unmarshal(buf, &jsmap); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if config.Debug {
|
|
||||||
log.Printf("%v: %v", n, jsmap)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range f {
|
|
||||||
d(n, jsmap)
|
|
||||||
}
|
|
||||||
buf, err = json.MarshalIndent(jsmap, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
buf = append(buf, '\n')
|
|
||||||
|
|
||||||
if config.Debug {
|
|
||||||
os.Stdout.Write(buf)
|
|
||||||
} else {
|
|
||||||
ioutil.WriteFile(n, buf, 0666)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if config.Jehanne == "" {
|
|
||||||
log.Fatalf("Please set $JEHANNE")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(config.Args) == 0 {
|
|
||||||
config.Args = []string{config.Jehanne}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
flag.BoolVar(&config.Debug, "d", true, "Enable debug prints")
|
|
||||||
flag.Parse()
|
|
||||||
config.Args = flag.Args()
|
|
||||||
for _, n := range config.Args {
|
|
||||||
err = filepath.Walk(n, func(name string, fi os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if fi.IsDir() {
|
|
||||||
if config.Except[fi.Name()] {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
n := fi.Name()
|
|
||||||
if len(n) < 5 || n[len(n)-5:] != ".json" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
todo := []fixup{cflags, removeempty, checkname}
|
|
||||||
if config.Except[n] {
|
|
||||||
todo = todo[1:]
|
|
||||||
}
|
|
||||||
log.Printf("process %s", name)
|
|
||||||
err = one(name, todo...)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s: %s\n", name, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("%v", err)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"debug/elf"
|
|
||||||
"encoding/binary"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Header struct {
|
|
||||||
Sz byte
|
|
||||||
_ byte
|
|
||||||
Core uint16
|
|
||||||
_ uint16
|
|
||||||
Ver byte
|
|
||||||
Sig byte
|
|
||||||
Time uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type pc uint64
|
|
||||||
|
|
||||||
type Record struct {
|
|
||||||
Header
|
|
||||||
pcs []pc
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Symbol struct {
|
|
||||||
Addr uint64
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Symbols []*Symbol
|
|
||||||
|
|
||||||
func (s Symbols) Len() int { return len(s) }
|
|
||||||
func (s Symbols) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
type ByAddress struct{ Symbols }
|
|
||||||
|
|
||||||
func (s ByAddress) Less(i, j int) bool { return s.Symbols[i].Addr < s.Symbols[j].Addr }
|
|
||||||
|
|
||||||
var (
|
|
||||||
profile = flag.String("profile", "", "name of file containing profile data")
|
|
||||||
debug = flag.Bool("d", false, "Debug printing")
|
|
||||||
kernel = flag.String("kernel", "", "kernel to profile against")
|
|
||||||
symbolTable []*Symbol
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadSymbols(kernel *elf.File) {
|
|
||||||
syms, err := kernel.Symbols()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sym := range syms {
|
|
||||||
value := sym.Value | 0xffffffff00000000
|
|
||||||
symbolTable = append(symbolTable, &Symbol{value, sym.Name})
|
|
||||||
}
|
|
||||||
sort.Sort(ByAddress{symbolTable})
|
|
||||||
}
|
|
||||||
|
|
||||||
func findFunction(pc pc) string {
|
|
||||||
addr := uint64(pc)
|
|
||||||
var prevSym *Symbol
|
|
||||||
for _, sym := range symbolTable {
|
|
||||||
if sym.Addr > addr && prevSym != nil {
|
|
||||||
return prevSym.Name
|
|
||||||
}
|
|
||||||
prevSym = sym
|
|
||||||
}
|
|
||||||
return "*** Not Found ***"
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
kernelElf, err := elf.Open(*kernel)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
loadSymbols(kernelElf)
|
|
||||||
|
|
||||||
backtraces, err := ioutil.ReadFile(*profile)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
b := bytes.NewBuffer(backtraces)
|
|
||||||
var numRecords int
|
|
||||||
var records []Record
|
|
||||||
for {
|
|
||||||
var h Header
|
|
||||||
if err := binary.Read(b, binary.LittleEndian, &h); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "header: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if *debug {
|
|
||||||
fmt.Fprintf(os.Stderr, "%d: %v\n", numRecords, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.Sig != 0xee {
|
|
||||||
fmt.Fprintf(os.Stderr, "Record %d: sig is 0x%x, not 0xee", numRecords, h.Sig)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
pcs := make([]pc, h.Sz)
|
|
||||||
if err := binary.Read(b, binary.LittleEndian, pcs); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "data: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
numRecords++
|
|
||||||
records = append(records, Record{Header: h, pcs: pcs})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, r := range records {
|
|
||||||
fmt.Printf("0x%x: ", r.Time)
|
|
||||||
for _, pc := range r.pcs {
|
|
||||||
fmt.Printf("[0x%x, %s] ", pc, findFunction(pc))
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"debug/elf"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var dry = flag.Bool("dryrun", true, "don't really do it")
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
a := flag.Args()
|
|
||||||
for _, n := range a {
|
|
||||||
f, err := elf.Open(n)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v %v\n", n, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s, err := f.Symbols()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v %v\n", n, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
usem := false
|
|
||||||
for _, v := range s {
|
|
||||||
if v.Name == "m" && v.Section == elf.SHN_UNDEF {
|
|
||||||
usem = true
|
|
||||||
cf := strings.Split(n, ".")
|
|
||||||
globs, err := filepath.Glob("../*/" + cf[0] + ".c")
|
|
||||||
if err != nil || len(globs) == 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v has NO source?\n", cf[0])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(globs) > 1 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Skipping %v has more than one source?\n", cf[0])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
file := globs[0]
|
|
||||||
fi, err := os.Stat(file)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
/* OK, read it in, write it out */
|
|
||||||
b, err := ioutil.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v: %v\n", file, err)
|
|
||||||
}
|
|
||||||
header := []byte("extern Mach *m; // REMOVE ME\n")
|
|
||||||
if bytes.Compare(header[:], b[0:len(header)]) == 0 {
|
|
||||||
fmt.Fprintf(os.Stderr, "%v already done; skipping\n", file)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out := append([]byte("typedef struct Mach Mach; extern Mach *m; // REMOVE ME\n"), b...)
|
|
||||||
if *dry {
|
|
||||||
fmt.Fprintf(os.Stderr, "Would do %v mode %v\n", file, fi.Mode())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(file, out, fi.Mode()); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Write %v failed: %v; git checkout %v\n", file, err, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !usem {
|
|
||||||
fmt.Fprintf(os.Stderr, "Ignored %v as it did not reference Mach *m\n", n)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Procssed %v as it did reference Mach *m\n", n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
// Run commands received from stdin in qemu
|
|
||||||
//
|
|
||||||
// -p prompt => prompt to expect (default "10.0.2.15#")
|
|
||||||
//
|
|
||||||
// ENVIRONMENT
|
|
||||||
// Needed: JEHANNE
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"flag"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"github.com/creack/pty"
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var prompt string
|
|
||||||
flag.StringVar(&prompt, "p", "10.0.2.15#", "the prompt to expect")
|
|
||||||
flag.Parse()
|
|
||||||
jehanne := os.Getenv("JEHANNE")
|
|
||||||
if jehanne == "" {
|
|
||||||
fmt.Printf("usage: cat cmds.rc | runqemu [-p prompt]\n")
|
|
||||||
fmt.Printf("error: missing $JEHANNE\n");
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if terminal.IsTerminal(0) {
|
|
||||||
fmt.Printf("usage: cat cmds.rc | runqemu [-p prompt]\n")
|
|
||||||
fmt.Printf("error: runqemu is intended for automation, pipe commands in.\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuCmd := "cd $JEHANNE/arch/amd64/kern && $JEHANNE/hacking/QA.sh\n"
|
|
||||||
qemuCmd = os.ExpandEnv(qemuCmd)
|
|
||||||
|
|
||||||
sh := exec.Command("/bin/sh")
|
|
||||||
qemu, err := pty.Start(sh)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("REGRESS start (%s): %s", qemuCmd, err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
qemu.WriteString(qemuCmd)
|
|
||||||
defer qemu.Close()
|
|
||||||
|
|
||||||
exitStatus := 0
|
|
||||||
|
|
||||||
qemuInput := make(chan string)
|
|
||||||
qemuOutputRaw := make(chan string)
|
|
||||||
wait := make(chan int)
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
qemuOut := make([]byte, 256)
|
|
||||||
for {
|
|
||||||
r, err := qemu.Read(qemuOut)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "error:", err)
|
|
||||||
wait <- 3
|
|
||||||
}
|
|
||||||
qemuOutputRaw <- string(qemuOut[0:r])
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func(){
|
|
||||||
line := ""
|
|
||||||
for {
|
|
||||||
s := <- qemuOutputRaw
|
|
||||||
line += s
|
|
||||||
if strings.Contains(line, prompt) {
|
|
||||||
if scanner.Scan() {
|
|
||||||
cmd := scanner.Text()
|
|
||||||
qemuInput <- fmt.Sprintf("%s\n", cmd)
|
|
||||||
} else {
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "error:", err)
|
|
||||||
wait <- 4
|
|
||||||
} else {
|
|
||||||
wait <- exitStatus
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("%s", line)
|
|
||||||
line = ""
|
|
||||||
} else if strings.ContainsAny(line, "\r\n") {
|
|
||||||
if strings.Contains(line, "FAIL") {
|
|
||||||
exitStatus = 5
|
|
||||||
}
|
|
||||||
fmt.Printf("%s", line)
|
|
||||||
line = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
go func(){
|
|
||||||
for {
|
|
||||||
s := <- qemuInput
|
|
||||||
i := 0;
|
|
||||||
for {
|
|
||||||
n, err := qemu.WriteString(s[i:])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "error:", err)
|
|
||||||
wait <- 6
|
|
||||||
}
|
|
||||||
i += n
|
|
||||||
if i == len(s) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
e := <- wait
|
|
||||||
if e == 0 {
|
|
||||||
fmt.Printf("\nDone.\n")
|
|
||||||
}
|
|
||||||
os.Exit(e)
|
|
||||||
}
|
|
@ -1,244 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Copyright 2012 the u-root Authors. All rights reserved
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
type (
|
|
||||||
chunk struct {
|
|
||||||
id int
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
echo = false
|
|
||||||
)
|
|
||||||
|
|
||||||
func comprefix(lines [][]byte) (int, int) {
|
|
||||||
var line0 []byte
|
|
||||||
len0 := 0
|
|
||||||
for _, ln := range lines {
|
|
||||||
if len(ln) > len0 {
|
|
||||||
line0 = ln
|
|
||||||
len0 = len(ln)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ndiff := 0
|
|
||||||
for i := range line0 {
|
|
||||||
nshort := 0
|
|
||||||
for _, ln := range lines {
|
|
||||||
if i >= len(ln) {
|
|
||||||
nshort++
|
|
||||||
} else if ln[i] != line0[i] {
|
|
||||||
ndiff++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ndiff > 0 {
|
|
||||||
return i, ndiff
|
|
||||||
}
|
|
||||||
if nshort > 0 {
|
|
||||||
return i, ndiff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(line0), ndiff
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
if len(os.Args) < 2 {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var conns []*net.TCPConn
|
|
||||||
for _, a := range os.Args[1:] {
|
|
||||||
port := "1522"
|
|
||||||
if !strings.Contains(a, ":") {
|
|
||||||
a = a + ":" + port
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpdst, err := net.ResolveTCPAddr("tcp", a)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := net.DialTCP("tcp", nil, tcpdst)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
conns = append(conns, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
if terminal.IsTerminal(0) {
|
|
||||||
unraw, err := terminal.MakeRaw(0)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer terminal.Restore(0, unraw)
|
|
||||||
|
|
||||||
sigc := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
|
|
||||||
go func() {
|
|
||||||
for _ = range sigc {
|
|
||||||
terminal.Restore(0, unraw)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
buf := make([]byte, 256)
|
|
||||||
for {
|
|
||||||
n, err := os.Stdin.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
}
|
|
||||||
for _, c := range conns {
|
|
||||||
c.CloseWrite() // I know, I know.. but it is handy sometimes.
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
buf = buf[0:n]
|
|
||||||
for i := range buf {
|
|
||||||
if echo {
|
|
||||||
fmt.Printf("%s", string(buf[i]))
|
|
||||||
}
|
|
||||||
if buf[i] == '\r' {
|
|
||||||
buf[i] = '\n'
|
|
||||||
if echo {
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range conns {
|
|
||||||
if _, err := c.Write(buf); err != nil {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
waitc := make(chan int)
|
|
||||||
chunkc := make(chan chunk)
|
|
||||||
for id, c := range conns {
|
|
||||||
go func(id int, c *net.TCPConn) {
|
|
||||||
for {
|
|
||||||
buf := make([]byte, 256)
|
|
||||||
n, err := c.Read(buf)
|
|
||||||
if err != nil {
|
|
||||||
if err != io.EOF {
|
|
||||||
fmt.Printf("%v\n", err)
|
|
||||||
}
|
|
||||||
c.Close()
|
|
||||||
waitc <- 1
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chunkc <- chunk{id, buf[0:n]}
|
|
||||||
}
|
|
||||||
}(id, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
act := make([][]byte, len(conns))
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
oldpfix := 0
|
|
||||||
insync := true
|
|
||||||
for {
|
|
||||||
chunk, more := <-chunkc
|
|
||||||
if !more {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
id := chunk.id
|
|
||||||
for _, b := range chunk.buf {
|
|
||||||
act[id] = append(act[id], b)
|
|
||||||
if false && b == '\b' {
|
|
||||||
act[id] = append(act[id], ' ')
|
|
||||||
act[id] = append(act[id], '\b')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* streams agree, so spit out all they agree on */
|
|
||||||
if insync {
|
|
||||||
newpfix, ndiff := comprefix(act)
|
|
||||||
if ndiff == 0 && newpfix > oldpfix {
|
|
||||||
os.Stdout.Write(act[id][oldpfix:newpfix])
|
|
||||||
for {
|
|
||||||
i := bytes.IndexByte(act[id][:newpfix], '\n')
|
|
||||||
if i == -1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for id := range act {
|
|
||||||
clen := copy(act[id], act[id][i+1:])
|
|
||||||
act[id] = act[id][0:clen]
|
|
||||||
}
|
|
||||||
newpfix = newpfix - (i + 1)
|
|
||||||
}
|
|
||||||
oldpfix = newpfix
|
|
||||||
}
|
|
||||||
|
|
||||||
if ndiff > 0 {
|
|
||||||
insync = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* streams disagree, first to newline completes from oldpfix on.
|
|
||||||
* the outer loop is just for transitioning from insync, where
|
|
||||||
* a leader may be several lines ahead
|
|
||||||
*/
|
|
||||||
if !insync {
|
|
||||||
for id := range act {
|
|
||||||
for {
|
|
||||||
i := bytes.IndexByte(act[id], '\n')
|
|
||||||
if i != -1 {
|
|
||||||
if oldpfix == 0 {
|
|
||||||
fmt.Fprintf(os.Stdout, "[%d]", id)
|
|
||||||
}
|
|
||||||
os.Stdout.Write(act[id][oldpfix : i+1])
|
|
||||||
clen := copy(act[id], act[id][i+1:])
|
|
||||||
act[id] = act[id][0:clen]
|
|
||||||
oldpfix = 0
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* try for prompt (or sheer luck) */
|
|
||||||
if _, ndiff := comprefix(act); ndiff == 0 {
|
|
||||||
insync = true
|
|
||||||
oldpfix = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
waitc <- 1
|
|
||||||
}()
|
|
||||||
|
|
||||||
for _ = range conns {
|
|
||||||
<-waitc
|
|
||||||
}
|
|
||||||
close(chunkc)
|
|
||||||
<-waitc
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Jehanne.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016-2019 Giacomo Tesio <giacomo@tesio.it>
|
|
||||||
*
|
|
||||||
* Jehanne 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, version 3 of the License.
|
|
||||||
*
|
|
||||||
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
const gplHeader string = `/*
|
|
||||||
* This file is part of Jehanne.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2016-2019 Giacomo Tesio <giacomo@tesio.it>
|
|
||||||
*
|
|
||||||
* Jehanne 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, version 3 of the License.
|
|
||||||
*
|
|
||||||
* Jehanne 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 Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
/* automatically generated by usyscalls */
|
|
||||||
`
|
|
||||||
|
|
||||||
type SyscallConf struct {
|
|
||||||
Ret []string
|
|
||||||
Args []string
|
|
||||||
Name string
|
|
||||||
Id uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type Sysconf struct {
|
|
||||||
Syscalls []SyscallConf
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyscallWrapper struct {
|
|
||||||
Id uint32
|
|
||||||
Name string
|
|
||||||
FuncArgs string
|
|
||||||
MacroArgs string
|
|
||||||
VarValues []string
|
|
||||||
Vars []string
|
|
||||||
AsmArgs string
|
|
||||||
AsmClobbers string
|
|
||||||
RetType string
|
|
||||||
}
|
|
||||||
|
|
||||||
type HeaderCode struct {
|
|
||||||
Wrappers []SyscallWrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func usage(msg string) {
|
|
||||||
fmt.Fprint(os.Stderr, msg)
|
|
||||||
fmt.Fprint(os.Stderr, "Usage: usyscalls header|code path/to/sysconf.json\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func argTypeName(t string) string{
|
|
||||||
switch(t){
|
|
||||||
case "int", "int32_t":
|
|
||||||
return "i"
|
|
||||||
case "unsigned int", "uint32_t":
|
|
||||||
/* unsigned int is reserved for flags */
|
|
||||||
return "ui"
|
|
||||||
case "long", "int64_t":
|
|
||||||
return "l"
|
|
||||||
case "unsigned long", "uint64_t":
|
|
||||||
return "ul"
|
|
||||||
case "void*", "uint8_t*", "const void*", "const uint8_t*":
|
|
||||||
return "p"
|
|
||||||
case "int32_t*", "int*", "const int32_t*", "const int*":
|
|
||||||
return "p"
|
|
||||||
case "const char*", "char*":
|
|
||||||
return "p"
|
|
||||||
case "const char**", "char**":
|
|
||||||
return "p"
|
|
||||||
}
|
|
||||||
return " [?? " + t + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func argRegister(index int, t string) string{
|
|
||||||
prefix := ""
|
|
||||||
switch(t){
|
|
||||||
case "int", "unsigned int", "uint32_t", "int32_t":
|
|
||||||
prefix = "e"
|
|
||||||
default:
|
|
||||||
prefix = "r"
|
|
||||||
}
|
|
||||||
switch(index){
|
|
||||||
case 0:
|
|
||||||
return prefix + "di";
|
|
||||||
case 1:
|
|
||||||
return prefix + "si";
|
|
||||||
case 2:
|
|
||||||
return prefix + "dx";
|
|
||||||
case 3:
|
|
||||||
return "r10";
|
|
||||||
case 4:
|
|
||||||
return "r8";
|
|
||||||
case 5:
|
|
||||||
return "r9";
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHeaderData(calls []SyscallConf) *HeaderCode {
|
|
||||||
code := new(HeaderCode)
|
|
||||||
for _, call := range(calls) {
|
|
||||||
wcall := new(SyscallWrapper)
|
|
||||||
wcall.Id = call.Id
|
|
||||||
wcall.Name = call.Name
|
|
||||||
wcall.RetType = call.Ret[0]
|
|
||||||
|
|
||||||
clobberMemory := false
|
|
||||||
wcall.AsmClobbers = "\"cc\", \"rcx\", \"r11\""
|
|
||||||
wcall.AsmArgs = fmt.Sprintf("\"0\"(%d)", wcall.Id)
|
|
||||||
for i, a := range(call.Args){
|
|
||||||
typeName := argTypeName(a)
|
|
||||||
if i > 0 {
|
|
||||||
wcall.FuncArgs += ", "
|
|
||||||
wcall.MacroArgs += ", "
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(a, "*") && !strings.HasPrefix(a, "const"){
|
|
||||||
clobberMemory = true
|
|
||||||
}
|
|
||||||
wcall.FuncArgs += fmt.Sprintf("%s a%d", a, i)
|
|
||||||
wcall.MacroArgs += fmt.Sprintf("/* %s */ a%d", a, i)
|
|
||||||
if typeName == "p" {
|
|
||||||
wcall.VarValues = append(wcall.VarValues, fmt.Sprintf("_sysargs[%d].%s = ((volatile void*)(a%d)); \\\n\t", i, typeName, i))
|
|
||||||
} else {
|
|
||||||
wcall.VarValues = append(wcall.VarValues, fmt.Sprintf("_sysargs[%d].%s = (a%d); \\\n\t", i, typeName, i))
|
|
||||||
}
|
|
||||||
wcall.Vars = append(wcall.Vars, fmt.Sprintf("register %s __r%d asm(\"%s\") = _sysargs[%d].%s; \\\n\t", a, i, argRegister(i, a), i, argTypeName(a)))
|
|
||||||
wcall.AsmArgs += fmt.Sprintf(", \"r\"(__r%d)", i)
|
|
||||||
}
|
|
||||||
if clobberMemory {
|
|
||||||
wcall.AsmClobbers += ", \"memory\""
|
|
||||||
}
|
|
||||||
code.Wrappers = append(code.Wrappers, *wcall)
|
|
||||||
}
|
|
||||||
|
|
||||||
return code
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateSyscallTable(calls []SyscallConf){
|
|
||||||
code := getHeaderData(calls)
|
|
||||||
tmpl, err := template.New("tab.c").Parse(`
|
|
||||||
{{ range .Wrappers }}"{{ .Name }}", (int(*)()) sys_{{ .Name }},
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(os.Stdout, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateLibcCode(calls []SyscallConf){
|
|
||||||
code := getHeaderData(calls)
|
|
||||||
tmpl, err := template.New("syscalls.c").Parse(gplHeader + `
|
|
||||||
#define PORTABLE_SYSCALLS
|
|
||||||
#include <u.h>
|
|
||||||
|
|
||||||
{{ range .Wrappers }}
|
|
||||||
#pragma weak sys_{{ .Name }}
|
|
||||||
{{ .RetType }}
|
|
||||||
sys_{{ .Name }}({{ .FuncArgs }})
|
|
||||||
{
|
|
||||||
register {{ .RetType }} __ret asm ("rax");
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"movq %%rcx, %%r10" "\n\t"
|
|
||||||
"movq ${{ .Id }}, %%rax" "\n\t"
|
|
||||||
"syscall"
|
|
||||||
: "=r" (__ret)
|
|
||||||
: /* args are ready */
|
|
||||||
: {{ .AsmClobbers }}
|
|
||||||
);
|
|
||||||
return __ret;
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(os.Stdout, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateSyscallHeader(calls []SyscallConf){
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"title": strings.Title,
|
|
||||||
}
|
|
||||||
code := getHeaderData(calls)
|
|
||||||
tmpl, err := template.New("syscall.h").Funcs(funcMap).Parse(gplHeader + `
|
|
||||||
typedef enum Syscalls
|
|
||||||
{
|
|
||||||
{{ range .Wrappers }} Sys{{ .Name|title }} = {{ .Id }},
|
|
||||||
{{ end }}} Syscalls;
|
|
||||||
|
|
||||||
#ifndef KERNEL
|
|
||||||
|
|
||||||
{{ range .Wrappers }}extern {{ .RetType }} sys_{{ .Name }}({{ .FuncArgs }});
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
`)
|
|
||||||
err = tmpl.Execute(os.Stdout, code)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if flag.NArg() != 2 {
|
|
||||||
usage("no path to sysconf.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(flag.Arg(1))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var sysconf Sysconf
|
|
||||||
err = json.Unmarshal(buf, &sysconf)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
mode := flag.Arg(0)
|
|
||||||
switch(mode){
|
|
||||||
case "header":
|
|
||||||
generateSyscallHeader(sysconf.Syscalls)
|
|
||||||
break
|
|
||||||
case "code":
|
|
||||||
generateLibcCode(sysconf.Syscalls)
|
|
||||||
break
|
|
||||||
case "tab":
|
|
||||||
generateSyscallTable(sysconf.Syscalls)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
45
src/jehanne/cmd/vendor/doc.go
vendored
45
src/jehanne/cmd/vendor/doc.go
vendored
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
Vendor is a tool to vendor software for Jehanne.
|
|
||||||
|
|
||||||
It downloads a tarball, verifies it against supplied hashes, extracts it
|
|
||||||
into "upstream", modifies all the files to be read-only, and then commits
|
|
||||||
the results.
|
|
||||||
|
|
||||||
When invoked with the flag `-check` it verify that the files present in
|
|
||||||
a previously vendorized "upstream" folder match those in the downloaded tarball.
|
|
||||||
|
|
||||||
Vendor is purposely unhelpful and un-customisable.
|
|
||||||
|
|
||||||
VENDORFILE
|
|
||||||
|
|
||||||
It requires a "vendor.json" file in the current directory with the following
|
|
||||||
structure:
|
|
||||||
|
|
||||||
{
|
|
||||||
"Upstream":"",
|
|
||||||
"Digest": {
|
|
||||||
"":""
|
|
||||||
},
|
|
||||||
"Compress":"",
|
|
||||||
"RemovePrefix": true,
|
|
||||||
"Exclude": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
"Upstream" is the URL to fetch a tarball from.
|
|
||||||
|
|
||||||
"Digest" is a map of algorithm-hash pairs for calculating checksums. All
|
|
||||||
of the sha functions in the go standard library are supported except for sha1.
|
|
||||||
The hash is hex-encoded, just like sha*sum output.
|
|
||||||
|
|
||||||
"Compress" is the compression type of the tarball. Gzip and bzip are
|
|
||||||
supported. If this key is omitted, the tarball is assumed to be uncompressed.
|
|
||||||
|
|
||||||
"RemovePrefix" is a boolean toggle for if the first element of files in the
|
|
||||||
archive should be removed. Defaults to false if omitted.
|
|
||||||
|
|
||||||
"Exclude" is an array of prefix strings for files that should not be
|
|
||||||
extracted. They are used as literal prefixes and not interpreted in any way.
|
|
||||||
*/
|
|
||||||
package main
|
|
248
src/jehanne/cmd/vendor/vendor.go
vendored
248
src/jehanne/cmd/vendor/vendor.go
vendored
@ -1,248 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/tar"
|
|
||||||
"bytes"
|
|
||||||
"compress/bzip2"
|
|
||||||
"compress/gzip"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"hash"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ignore = "*\n!.gitignore\n"
|
|
||||||
dirPermissions = 0755
|
|
||||||
)
|
|
||||||
|
|
||||||
type V struct {
|
|
||||||
Upstream string
|
|
||||||
Digest map[string]string
|
|
||||||
Compress string
|
|
||||||
RemovePrefix bool
|
|
||||||
Exclude []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.SetFlags(log.Lshortfile | log.LstdFlags)
|
|
||||||
|
|
||||||
justCheck := flag.Bool("check", false, "verify the code in upstream/")
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if(*justCheck && !repositoryIsClean()){
|
|
||||||
log.Fatal("cannot verify upstream/ files: working directory not clean")
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := ioutil.ReadFile("vendor.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
vendor := &V{}
|
|
||||||
if err := json.Unmarshal(f, vendor); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat("upstream"); err == nil {
|
|
||||||
log.Println("recreating upstream")
|
|
||||||
if(*justCheck){
|
|
||||||
run("rm", "-r", "-f", "upstream")
|
|
||||||
} else {
|
|
||||||
run("git", "rm", "-r", "-f", "upstream")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(*justCheck){
|
|
||||||
log.Fatalf("Cannot verify upstream/ as it does not exists.")
|
|
||||||
}
|
|
||||||
os.MkdirAll("patch", dirPermissions)
|
|
||||||
os.MkdirAll("jehanne", dirPermissions)
|
|
||||||
ig, err := os.Create(path.Join("jehanne", ".gitignore"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer ig.Close()
|
|
||||||
if _, err := ig.WriteString(ignore); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
run("git", "add", ig.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := do(vendor, *justCheck); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(*justCheck){
|
|
||||||
if(repositoryIsClean()){
|
|
||||||
log.Printf("the files in upstream/ matches those in "+path.Base(vendor.Upstream))
|
|
||||||
} else {
|
|
||||||
log.Fatalf("the files in upstream/ does not match those in "+path.Base(vendor.Upstream))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
run("git", "add", "vendor.json")
|
|
||||||
run("git", "commit", "-s", "-m", "vendor: pull in "+path.Base(vendor.Upstream))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func repositoryIsClean() bool {
|
|
||||||
out, err := exec.Command("git", "status", "--porcelain").Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if(len(out) > 0){
|
|
||||||
log.Println("git status --porcelain");
|
|
||||||
log.Println(string(out))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func do(v *V, justCheck bool) error {
|
|
||||||
name := fetch(v)
|
|
||||||
f, err := os.Open(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer os.Remove(name)
|
|
||||||
|
|
||||||
var unZ io.Reader
|
|
||||||
switch v.Compress {
|
|
||||||
case "gzip":
|
|
||||||
unZ, err = gzip.NewReader(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "bzip2":
|
|
||||||
unZ = bzip2.NewReader(f)
|
|
||||||
default:
|
|
||||||
unZ = f
|
|
||||||
}
|
|
||||||
|
|
||||||
ar := tar.NewReader(unZ)
|
|
||||||
h, err := ar.Next()
|
|
||||||
untar:
|
|
||||||
for ; err == nil; h, err = ar.Next() {
|
|
||||||
n := h.Name
|
|
||||||
if v.RemovePrefix {
|
|
||||||
n = strings.SplitN(n, "/", 2)[1]
|
|
||||||
}
|
|
||||||
for _, ex := range v.Exclude {
|
|
||||||
if strings.HasPrefix(n, ex) {
|
|
||||||
continue untar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n = path.Join("upstream", n)
|
|
||||||
if h.FileInfo().IsDir() {
|
|
||||||
os.MkdirAll(n, dirPermissions)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
os.MkdirAll(path.Dir(n), dirPermissions)
|
|
||||||
out, err := os.Create(n)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := io.Copy(out, ar); n != h.Size || err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Close()
|
|
||||||
}
|
|
||||||
if err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if(justCheck){
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
return run("git", "add", "upstream")
|
|
||||||
}
|
|
||||||
|
|
||||||
type match struct {
|
|
||||||
hash.Hash
|
|
||||||
Good []byte
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m match) OK() bool {
|
|
||||||
return bytes.Equal(m.Good, m.Hash.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetch(v *V) string {
|
|
||||||
if len(v.Digest) == 0 {
|
|
||||||
log.Fatal("no checksums specifed")
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := ioutil.TempFile("", "cmdVendor")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", v.Upstream, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
client := &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
DisableCompression: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
res, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
var digests []match
|
|
||||||
for k, v := range v.Digest {
|
|
||||||
g, err := hex.DecodeString(v)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
switch k {
|
|
||||||
case "sha224":
|
|
||||||
digests = append(digests, match{sha256.New224(), g, k})
|
|
||||||
case "sha256":
|
|
||||||
digests = append(digests, match{sha256.New(), g, k})
|
|
||||||
case "sha384":
|
|
||||||
digests = append(digests, match{sha512.New384(), g, k})
|
|
||||||
case "sha512":
|
|
||||||
digests = append(digests, match{sha512.New(), g, k})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ws := make([]io.Writer, len(digests))
|
|
||||||
for i := range digests {
|
|
||||||
ws[i] = digests[i]
|
|
||||||
}
|
|
||||||
w := io.MultiWriter(ws...)
|
|
||||||
|
|
||||||
if _, err := io.Copy(f, io.TeeReader(res.Body, w)); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
for _, h := range digests {
|
|
||||||
if !h.OK() {
|
|
||||||
log.Fatalf("mismatched %q hash\n\tWanted %x\n\tGot %x\n", h.Name, h.Good, h.Hash.Sum(nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return f.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(exe string, arg ...string) error {
|
|
||||||
cmd := exec.Command(exe, arg...)
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
1
src/netcat
Submodule
1
src/netcat
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 607401678236b608280b291ad849a109b8d9a8f2
|
1
src/trampoline
Submodule
1
src/trampoline
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 1d47bf91a6d4828038e9fbd11508c90fc983dce0
|
1
src/u9fs
Submodule
1
src/u9fs
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit d65923fd17e8b158350d3ccd6a4e32b89b15014a
|
1
third_party/src/github.com/lionkov/ninep
vendored
1
third_party/src/github.com/lionkov/ninep
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit aed6e1e7aa37744dba150fa2974f322813d23478
|
|
Loading…
x
Reference in New Issue
Block a user