Initial commit

This commit is contained in:
domenico
2025-06-24 16:03:39 +02:00
commit f3256cdaf2
6949 changed files with 1441681 additions and 0 deletions

42
scripts/arm-magic.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env bash
#
# Empty/wrong machtype-workaround generator
#
# Copyright (C) 2006-2012 Imre Kaloz <kaloz@openwrt.org>
# based on linux/arch/arm/boot/compressed/head-xscale.S
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# NOTE: for now it's for only IXP4xx in big endian mode
# list of supported boards, in "boardname machtypeid" format
for board in "avila 526" "gateway7001 731" "nslu2 597" "nas100d 865" "wg302v1 889" "wg302v2 890" "pronghorn 928" "pronghornmetro 1040" "compex 1273" "wrt300nv2 1077" "loft 849" "dsmg600 964" "fsg3 1091" "ap1000 1543" "tw2662 1658" "tw5334 1664" "ixdpg425 604" "cambria 1468" "sidewinder 1041" "ap42x 4418"
do
set -- $board
hexid=$(printf %x\\n $2)
if [ "$2" -lt "256" ]; then
# we have a low machtypeid, we just need a "mov" (e3a)
printf "\xe3\xa0\x10\x$hexid" > $BIN_DIR/$IMG_PREFIX-$1-zImage
else
# we have a high machtypeid, we need a "mov" (e3a) and an "orr" (e38)
if [ "$2" -lt "4096" ]; then
printf "\xe3\xa0\x10\x$(echo $hexid|cut -b "2 3")\xe3\x81\x1c\x$(echo $hexid|cut -b 1)" > $BIN_DIR/$IMG_PREFIX-$1-zImage
else
printf "\xe3\xa0\x10\x$(echo $hexid|cut -b "3 4")\xe3\x81\x1c\x$(echo $hexid|cut -b "1 2")" > $BIN_DIR/$IMG_PREFIX-$1-zImage
fi
fi
# generate the image
cat $BIN_DIR/$IMG_PREFIX-zImage >> $BIN_DIR/$IMG_PREFIX-$1-zImage
done

162
scripts/brcmImage.pl Executable file
View File

@@ -0,0 +1,162 @@
#!/usr/bin/env perl
#
# Copyright (C) 2009 Henk Vergonet <Henk.Vergonet@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Description:
# Replacement for brcmImagebuilder
#
# Disclaimer:
# Use this software at your own risk.
#
# Changelog:
# 2009-01-01 Henk.Vergonet at gmail.com
#
use strict;
use Getopt::Std;
use Compress::Zlib;
my $version = "0.1";
my %arg = (
o => 'bcm963xx_fs_kernel',
b => 'OpenWrt',
c => '6348',
s => 64,
f => 0xbfc00000,
x => 0x00010000,
a => 0x80010000,
e => 0x80010000,
i => 2,
);
my $prog = $0;
$prog =~ s/^.*\///;
getopts("r:k:o:lc:b:s:f:i:a:e:tpvh", \%arg);
die "usage: $prog ~opts~
-r <file> : input rootfs file
-k <file> : input kernel file
-o <file> : output image file, default $arg{o}
-l : littleendian system, default ".($arg{l} ? 'yes' : 'no')."
-c <chipid> : default $arg{c}
-b <boardid> : default $arg{b}
-s <size_kb> : erase sise flash, default $arg{s}
-f <baseaddr> : flash base, default ".sprintf('0x%x', $arg{f})."
-x <cfelen> : length of cfe, default ".sprintf('0x%x', $arg{x})."
-i : 2=dual image, default $arg{i}
-a <loadaddr> : Kernel load address, default ".sprintf('0x%x', $arg{a})."
-e <entryaddr>: Kernel entry address, default ".sprintf('0x%x', $arg{e})."
-t : Prefix kernel with load,entry,size
-p : Add a 'gOtO' partition
-v : be more verbose
-h : help, version $version
EXAMPLES:
$prog -k kern -r rootfs
" if $arg{h} || !$arg{k} || !$arg{r};
sub Read_Image
{
open my $fh, $_[0] or die "open $_[0]: $!";
local $/; # Set input to "slurp" mode.
my $buf = <$fh>;
close $fh;
return $buf;
}
sub Padlen
{
my $p = $_[0] % $_[1];
return ($p ? $_[1] - $p : 0);
}
sub Pad
{
my ($buf, $off, $bs) = @_[0..2];
$buf .= chr(255) x Padlen(length($buf) + $off, $bs);
return $buf;
}
sub bcmImage
{
my ($k, $f) = @_[0..1];
my $tmp = $arg{x} + 0x100 + $arg{f};
# regular: rootfs+kernel
my ($img, $fa, $ka) = ( $f.$k, $tmp, $tmp + length($f) );
# test: kernel+rootfs
# my ($img, $fa, $ka) = ( $k.$f, $tmp + length($k), $tmp );
$fa = 0 unless length($f);
my $hdr = pack("a4a20a14a6a16a2a10a12a10a12a10a12a10a2a2a74Na16",
'6',
'LinuxInside',
'ver. 2.0',
$arg{c},
$arg{b},
($arg{l} ? '0' : '1'),
length($img),
'0',
'0',
$fa,
length($f),
$ka,
length($k),
($arg{i}==2 ? '1' : '0'),
'', # if 1, the image is INACTIVE; if 0, active
'',
~crc32($k, crc32($f)),
'');
$hdr .= pack('Na16', ~crc32($hdr), '');
printf "kernel at 0x%x length 0x%x(%u)\n", $ka, length($k), length($k)
if $arg{v};
printf "rootfs at 0x%x length 0x%x(%u)\n", $fa, length($f), length($f)
if $arg{v};
open(FO, ">$arg{o}");
print FO $hdr;
print FO $img;
close FO;
}
# MAIN
my $kern = Read_Image $arg{k};
my $root = Read_Image $arg{r};
$kern = pack('NNN', $arg{a}, $arg{e}, length($kern)).$kern if $arg{t};
# specific fixup for the CFE that expects rootfs-kernel order
if ($arg{p}) {
$kern = Pad($kern, 0x10c, $arg{s} * 1024);
my $dummy_root = pack('a4NN',
'gOtO',
length($kern)+12,
length($root)+Padlen(length($root), $arg{s} * 1024)
);
$kern .= $root;
$root = $dummy_root;
}
bcmImage($kern, $root);

212
scripts/bundle-libraries.sh Executable file
View File

@@ -0,0 +1,212 @@
#!/usr/bin/env bash
#
# Script to install host system binaries along with required libraries.
#
# Copyright (C) 2012-2017 Jo-Philipp Wich <jo@mein.io>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
DIR="$1"; shift
_cp() {
cp ${VERBOSE:+-v} -L "$1" "$2" || {
echo "cp($1 $2) failed" >&2
exit 1
}
}
_mv() {
mv ${VERBOSE:+-v} "$1" "$2" || {
echo "mv($1 $2) failed" >&2
exit 1
}
}
_md() {
mkdir ${VERBOSE:+-v} -p "$1" || {
echo "mkdir($1) failed" >&2
exit 2
}
}
_ln() {
ln ${VERBOSE:+-v} -sf "$1" "$2" || {
echo "ln($1 $2) failed" >&2
exit 3
}
}
_relpath() {
local base="$(readlink -f "$1")"
local dest="$(readlink -f "$2")"
local up
[ -d "$base" ] || base="${base%/*}"
[ -d "$dest" ] || dest="${dest%/*}"
while true; do
case "$base"
in "$dest"/*)
echo "$up/${base#$dest/}"
break
;;
*)
dest="${dest%/*}"
up="${up:+$up/}.."
;;
esac
done
}
_runas_so() {
cat <<-EOT | ${CC:-gcc} -x c -fPIC -shared -o "$1" -
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int mangle_arg0(int argc, char **argv, char **env) {
char *arg0 = getenv("RUNAS_ARG0");
if (arg0) {
argv[0] = arg0;
unsetenv("RUNAS_ARG0");
}
return 0;
}
#ifdef __APPLE__
__attribute__((section("__DATA,__mod_init_func")))
#else
__attribute__((section(".init_array")))
#endif
static void *mangle_arg0_constructor = &mangle_arg0;
EOT
[ -x "$1" ] || {
echo "compiling preload library failed" >&2
exit 5
}
}
_patch_ldso() {
_cp "$1" "$1.patched"
sed -i -e 's,/\(usr\|lib\|etc\)/,/###/,g' "$1.patched"
if "$1.patched" 2>&1 | grep -q -- --library-path; then
_mv "$1.patched" "$1"
else
echo "binary patched ${1##*/} not executable, using original" >&2
rm -f "$1.patched"
fi
}
_patch_glibc() {
_cp "$1" "$1.patched"
sed -i -e 's,/usr/\(\(lib\|share\)/locale\),/###/\1,g' "$1.patched"
if "$1.patched" 2>&1 | grep -q -- GNU; then
_mv "$1.patched" "$1"
else
echo "binary patched ${1##*/} not executable, using original" >&2
rm -f "$1.patched"
fi
}
should_be_patched() {
local bin="$1"
[ -x "$bin" ] || return 1
case "$bin" in
*.so|*.so.[0-9]*)
return 1
;;
*)
file "$bin" | grep -sqE "ELF.*(executable|interpreter)" && return 0
;;
esac
return 1
}
for LDD in ${PATH//://ldd }/ldd; do
"$LDD" --version >/dev/null 2>/dev/null && break
LDD=""
done
[ -n "$LDD" -a -x "$LDD" ] || LDD=
for BIN in "$@"; do
[ -n "$BIN" -a -n "$DIR" ] || {
echo "Usage: $0 <destdir> <executable> ..." >&2
exit 1
}
[ ! -d "$DIR/lib" ] && {
_md "$DIR/lib"
_md "$DIR/usr"
_ln "../lib" "$DIR/usr/lib"
}
[ ! -x "$DIR/lib/runas.so" ] && {
_runas_so "$DIR/lib/runas.so"
}
LDSO=""
[ -n "$LDD" ] && should_be_patched "$BIN" && {
for token in $("$LDD" "$BIN" 2>/dev/null); do
case "$token" in */*.so*)
dest="$DIR/lib/${token##*/}"
ddir="${dest%/*}"
case "$token" in
*/ld-*.so*) LDSO="${token##*/}" ;;
esac
[ -f "$token" -a ! -f "$dest" ] && {
_md "$ddir"
_cp "$token" "$dest"
case "$token" in
*/ld-*.so*) _patch_ldso "$dest" ;;
*/libc.so.6) _patch_glibc "$dest" ;;
esac
}
;; esac
done
}
# is a dynamically linked executable
if [ -n "$LDSO" ]; then
echo "Bundling ${BIN##*/}"
RUNDIR="$(readlink -f "$BIN")"; RUNDIR="${RUNDIR%/*}"
RUN="${LDSO#ld-}"; RUN="run-${RUN%%.so*}.sh"
REL="$(_relpath "$DIR/lib" "$BIN")"
_mv "$BIN" "$RUNDIR/.${BIN##*/}.bin"
cat <<-EOF > "$BIN"
#!/usr/bin/env bash
dir="\$(dirname "\$0")"
export RUNAS_ARG0="\$0"
export LD_PRELOAD="\$dir/${REL:+$REL/}runas.so"
exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/.${BIN##*/}.bin" "\$@"
EOF
chmod ${VERBOSE:+-v} 0755 "$BIN"
fi
done

3491
scripts/checkpatch.pl Executable file

File diff suppressed because it is too large Load Diff

12
scripts/clang-gcc-wrapper Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
_cc="${HOSTCC_REAL:-gcc}"
case "$1" in
-print-file-name=*)
dirs="$($_cc -print-search-dirs | grep -m1 libraries | sed -e 's,:, ,' -e 's,.* =,,')"
dirs="$dirs /usr/lib /usr/local/lib"
find $dirs -name "${1#*=}" | head -n1
;;
*)
exec $_cc "$@"
;;
esac

25
scripts/clean-package.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
IFS=$'\n'
[ -n "$1" -a -n "$2" ] || {
echo "Usage: $0 <file> <directory>"
exit 1
}
[ -f "$1" -a -d "$2" ] || {
echo "File/directory not found"
exit 1
}
cat "$1" | (
cd "$2"
while read entry; do
[ -n "$entry" ] || break
[ -f "$entry" ] && rm -f $entry
done
)
sort -r "$1" | (
cd "$2"
while read entry; do
[ -n "$entry" ] || break
[ -d "$entry" ] && rmdir "$entry" > /dev/null 2>&1
done
)
true

177
scripts/cleanfile Executable file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env perl
#
# Clean a text file -- or directory of text files -- of stealth whitespace.
# WARNING: this can be a highly destructive operation. Use with caution.
#
use bytes;
use File::Basename;
use warnings;
# Default options
$max_width = 79;
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
{
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($lo) = '';
my $pos = 0;
my $nsp = 0;
my($i, $c);
for ($i = 0; $i < length($li); $i++) {
$c = substr($li, $i, 1);
if ($c eq "\t") {
my $npos = ($pos+$nsp+8) & ~7;
my $ntab = ($npos >> 3) - ($pos >> 3);
$lo .= "\t" x $ntab;
$pos = $npos;
$nsp = 0;
} elsif ($c eq "\n" || $c eq "\r") {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos = 0;
} elsif ($c eq " ") {
$nsp++;
} else {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos++;
}
}
$lo .= " " x $nsp;
return $lo;
}
# Compute the visual width of a string
sub strwidth($) {
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($c, $i);
my $pos = 0;
my $mlen = 0;
for ($i = 0; $i < length($li); $i++) {
$c = substr($li,$i,1);
if ($c eq "\t") {
$pos = ($pos+8) & ~7;
} elsif ($c eq "\n") {
$mlen = $pos if ($pos > $mlen);
$pos = 0;
} else {
$pos++;
}
}
$mlen = $pos if ($pos > $mlen);
return $mlen;
}
$name = basename($0);
@files = ();
while (defined($a = shift(@ARGV))) {
if ($a =~ /^-/) {
if ($a eq '-width' || $a eq '-w') {
$max_width = shift(@ARGV)+0;
} else {
print STDERR "Usage: $name [-width #] files...\n";
exit 1;
}
} else {
push(@files, $a);
}
}
foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
print STDERR "$f: not a file\n";
next;
}
if (!open(FILE, '+<', $f)) {
print STDERR "$name: Cannot open file: $f: $!\n";
next;
}
binmode FILE;
# First, verify that it is not a binary file; consider any file
# with a zero byte to be a binary file. Is there any better, or
# additional, heuristic that should be applied?
$is_binary = 0;
while (read(FILE, $data, 65536) > 0) {
if ($data =~ /\0/) {
$is_binary = 1;
last;
}
}
if ($is_binary) {
print STDERR "$name: $f: binary file\n";
next;
}
seek(FILE, 0, 0);
$in_bytes = 0;
$out_bytes = 0;
$blank_bytes = 0;
@blanks = ();
@lines = ();
$lineno = 0;
while ( defined($line = <FILE>) ) {
$lineno++;
$in_bytes += length($line);
$line =~ s/[ \t\r]*$//; # Remove trailing spaces
$line = clean_space_tabs($line);
if ( $line eq "\n" ) {
push(@blanks, $line);
$blank_bytes += length($line);
} else {
push(@lines, @blanks);
$out_bytes += $blank_bytes;
push(@lines, $line);
$out_bytes += length($line);
@blanks = ();
$blank_bytes = 0;
}
$l_width = strwidth($line);
if ($max_width && $l_width > $max_width) {
print STDERR
"$f:$lineno: line exceeds $max_width characters ($l_width)\n";
}
}
# Any blanks at the end of the file are discarded
if ($in_bytes != $out_bytes) {
# Only write to the file if changed
seek(FILE, 0, 0);
print FILE @lines;
if ( !defined($where = tell(FILE)) ||
!truncate(FILE, $where) ) {
die "$name: Failed to truncate modified file: $f: $!\n";
}
}
close(FILE);
}

259
scripts/cleanpatch Executable file
View File

@@ -0,0 +1,259 @@
#!/usr/bin/env perl
#
# Clean a patch file -- or directory of patch files -- of stealth whitespace.
# WARNING: this can be a highly destructive operation. Use with caution.
#
use bytes;
use File::Basename;
use warnings;
# Default options
$max_width = 79;
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
{
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($lo) = '';
my $pos = 0;
my $nsp = 0;
my($i, $c);
for ($i = 0; $i < length($li); $i++) {
$c = substr($li, $i, 1);
if ($c eq "\t") {
my $npos = ($pos+$nsp+8) & ~7;
my $ntab = ($npos >> 3) - ($pos >> 3);
$lo .= "\t" x $ntab;
$pos = $npos;
$nsp = 0;
} elsif ($c eq "\n" || $c eq "\r") {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos = 0;
} elsif ($c eq " ") {
$nsp++;
} else {
$lo .= " " x $nsp;
$pos += $nsp;
$nsp = 0;
$lo .= $c;
$pos++;
}
}
$lo .= " " x $nsp;
return $lo;
}
# Compute the visual width of a string
sub strwidth($) {
no bytes; # Tab alignment depends on characters
my($li) = @_;
my($c, $i);
my $pos = 0;
my $mlen = 0;
for ($i = 0; $i < length($li); $i++) {
$c = substr($li,$i,1);
if ($c eq "\t") {
$pos = ($pos+8) & ~7;
} elsif ($c eq "\n") {
$mlen = $pos if ($pos > $mlen);
$pos = 0;
} else {
$pos++;
}
}
$mlen = $pos if ($pos > $mlen);
return $mlen;
}
$name = basename($0);
@files = ();
while (defined($a = shift(@ARGV))) {
if ($a =~ /^-/) {
if ($a eq '-width' || $a eq '-w') {
$max_width = shift(@ARGV)+0;
} else {
print STDERR "Usage: $name [-width #] files...\n";
exit 1;
}
} else {
push(@files, $a);
}
}
foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
print STDERR "$f: not a file\n";
next;
}
if (!open(FILE, '+<', $f)) {
print STDERR "$name: Cannot open file: $f: $!\n";
next;
}
binmode FILE;
# First, verify that it is not a binary file; consider any file
# with a zero byte to be a binary file. Is there any better, or
# additional, heuristic that should be applied?
$is_binary = 0;
while (read(FILE, $data, 65536) > 0) {
if ($data =~ /\0/) {
$is_binary = 1;
last;
}
}
if ($is_binary) {
print STDERR "$name: $f: binary file\n";
next;
}
seek(FILE, 0, 0);
$in_bytes = 0;
$out_bytes = 0;
$lineno = 0;
@lines = ();
$in_hunk = 0;
$err = 0;
while ( defined($line = <FILE>) ) {
$lineno++;
$in_bytes += length($line);
if (!$in_hunk) {
if ($line =~
/^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
$minus_lines = $2;
$plus_lines = $4;
if ($minus_lines || $plus_lines) {
$in_hunk = 1;
@hunk_lines = ($line);
}
} else {
push(@lines, $line);
$out_bytes += length($line);
}
} else {
# We're in a hunk
if ($line =~ /^\+/) {
$plus_lines--;
$text = substr($line, 1);
$text =~ s/[ \t\r]*$//; # Remove trailing spaces
$text = clean_space_tabs($text);
$l_width = strwidth($text);
if ($max_width && $l_width > $max_width) {
print STDERR
"$f:$lineno: adds line exceeds $max_width ",
"characters ($l_width)\n";
}
push(@hunk_lines, '+'.$text);
} elsif ($line =~ /^\-/) {
$minus_lines--;
push(@hunk_lines, $line);
} elsif ($line =~ /^ /) {
$plus_lines--;
$minus_lines--;
push(@hunk_lines, $line);
} else {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
last;
}
if ($plus_lines < 0 || $minus_lines < 0) {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
last;
} elsif ($plus_lines == 0 && $minus_lines == 0) {
# End of a hunk. Process this hunk.
my $i;
my $l;
my @h = ();
my $adj = 0;
my $done = 0;
for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
$l = $hunk_lines[$i];
if (!$done && $l eq "+\n") {
$adj++; # Skip this line
} elsif ($l =~ /^[ +]/) {
$done = 1;
unshift(@h, $l);
} else {
unshift(@h, $l);
}
}
$l = $hunk_lines[0]; # Hunk header
undef @hunk_lines; # Free memory
if ($adj) {
die unless
($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
my $mstart = $1;
my $mlin = $2;
my $pstart = $3;
my $plin = $4;
my $tail = $5; # doesn't include the final newline
$l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
$mstart, $mlin, $pstart, $plin-$adj,
$tail);
}
unshift(@h, $l);
# Transfer to the output array
foreach $l (@h) {
$out_bytes += length($l);
push(@lines, $l);
}
$in_hunk = 0;
}
}
}
if ($in_hunk) {
print STDERR "$name: $f: malformed patch\n";
$err = 1;
}
if (!$err) {
if ($in_bytes != $out_bytes) {
# Only write to the file if changed
seek(FILE, 0, 0);
print FILE @lines;
if ( !defined($where = tell(FILE)) ||
!truncate(FILE, $where) ) {
die "$name: Failed to truncate modified file: $f: $!\n";
}
}
}
close(FILE);
}

78
scripts/combined-ext-image.sh Executable file
View File

@@ -0,0 +1,78 @@
#!/bin/sh
#
# Copyright (C) 2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# Write image header followed by all specified files
# The header is padded to 64k, format is:
# CE magic word ("Combined Extended Image") (2 bytes)
# <CE_VERSION> file format version field (2 bytes)
# <TYPE> short description of the target device (32 bytes)
# <NUM FILES> number of files following the header (2 byte)
# <file1_name> name of the first file (32 bytes)
# <file1_length> length of the first file encoded as zero padded 8 digit hex (8 bytes)
# <file1_md5> md5 checksum of the first file (32 bytes)
# <fileN_name> name of the Nth file (32 bytes)
# <fileN_length> length of the Nth file encoded as zero padded 8 digit hex (8 bytes)
# <fileN_md5> md5 checksum of the Nth file (32 bytes)
## version history
# * version 1: initial file format with num files / name / length / md5 checksum
set -e
ME="${0##*/}"
usage() {
echo "Usage: $ME <type> <ext filename> <file1> <filename1> [<file2> <filename2> <fileN> <filenameN>]"
[ "$IMG_OUT" ] && rm -f "$IMG_OUT"
exit 1
}
[ "$#" -lt 4 ] && usage
CE_VERSION=1
IMG_TYPE=$1; shift
IMG_OUT=$1; shift
FILE_NUM=$(($# / 2))
FILES=""
tmpdir="$( mktemp -d 2> /dev/null )"
if [ -z "$tmpdir" ]; then
# try OSX signature
tmpdir="$( mktemp -t 'ubitmp' -d )"
fi
if [ -z "$tmpdir" ]; then
exit 1
fi
trap "rm -rf $tmpdir" EXIT
IMG_TMP_OUT="${tmpdir}/out"
printf "CE%02x%-32s%02x" $CE_VERSION "$IMG_TYPE" $FILE_NUM > "${IMG_TMP_OUT}"
while [ "$#" -gt 1 ]
do
file=$1
filename=$2
[ ! -f "$file" ] && echo "$ME: Not a valid file: $file" && usage
FILES="$FILES $file"
md5=$(mkhash md5 "$file")
printf "%-32s%08x%32s" "$filename" $(stat -c "%s" "$file") "${md5%% *}" >> "${IMG_TMP_OUT}"
shift 2
done
[ "$#" -eq 1 ] && echo "$ME: Filename not specified: $1" && usage
mv "${IMG_TMP_OUT}" "${IMG_TMP_OUT}".tmp
dd if="${IMG_TMP_OUT}.tmp" of="${IMG_TMP_OUT}" bs=65536 conv=sync 2>/dev/null
rm "${IMG_TMP_OUT}".tmp
cat $FILES >> "${IMG_TMP_OUT}"
cp "${IMG_TMP_OUT}" "${IMG_OUT}"

34
scripts/combined-image.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
BLKSZ=65536
[ -f "$1" -a -f "$2" ] || {
echo "Usage: $0 <kernel image> <rootfs image> [output file]"
exit 1
}
IMAGE=${3:-openwrt-combined.img}
# Make sure provided images are 64k aligned.
kern="${IMAGE}.kernel"
root="${IMAGE}.rootfs"
dd if="$1" of="$kern" bs=$BLKSZ conv=sync 2>/dev/null
dd if="$2" of="$root" bs=$BLKSZ conv=sync 2>/dev/null
# Calculate md5sum over combined kernel and rootfs image.
md5=$(cat "$kern" "$root" | mkhash md5)
# Write image header followed by kernel and rootfs image.
# The header is padded to 64k, format is:
# CI magic word ("Combined Image")
# <kernel length> length of kernel encoded as zero padded 8 digit hex
# <rootfs length> length of rootfs encoded as zero padded 8 digit hex
# <md5sum> checksum of the combined kernel and rootfs image
( printf "CI%08x%08x%32s" \
$(stat -c "%s" "$kern") $(stat -c "%s" "$root") "${md5%% *}" | \
dd bs=$BLKSZ conv=sync;
cat "$kern" "$root"
) > ${IMAGE} 2>/dev/null
# Clean up.
rm -f "$kern" "$root"

1486
scripts/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

666
scripts/config.rpath Executable file
View File

@@ -0,0 +1,666 @@
#! /bin/sh
# Output a system dependent set of variables, describing how to set the
# run time search path of shared libraries in an executable.
#
# Copyright 1996-2007 Free Software Foundation, Inc.
# Taken from GNU libtool, 2001
# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# The first argument passed to this file is the canonical host specification,
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld
# should be set by the caller.
#
# The set of defined variables is at the end of this script.
# Known limitations:
# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer
# than 256 bytes, otherwise the compiler driver will dump core. The only
# known workaround is to choose shorter directory names for the build
# directory and/or the installation directory.
# All known linkers require a `.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
shrext=.so
host="$1"
host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
# Code taken from libtool.m4's _LT_CC_BASENAME.
for cc_temp in $CC""; do
case $cc_temp in
compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
\-*) ;;
*) break;;
esac
done
cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
wl=
if test "$GCC" = yes; then
wl='-Wl,'
else
case "$host_os" in
aix*)
wl='-Wl,'
;;
darwin*)
case $cc_basename in
xlc*)
wl='-Wl,'
;;
esac
;;
mingw* | cygwin* | pw32* | os2*)
;;
hpux9* | hpux10* | hpux11*)
wl='-Wl,'
;;
irix5* | irix6* | nonstopux*)
wl='-Wl,'
;;
newsos6)
;;
linux* | k*bsd*-gnu)
case $cc_basename in
icc* | ecc*)
wl='-Wl,'
;;
pgcc | pgf77 | pgf90)
wl='-Wl,'
;;
ccc*)
wl='-Wl,'
;;
como)
wl='-lopt='
;;
*)
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*)
wl='-Wl,'
;;
esac
;;
esac
;;
osf3* | osf4* | osf5*)
wl='-Wl,'
;;
rdos*)
;;
solaris*)
wl='-Wl,'
;;
sunos4*)
wl='-Qoption ld '
;;
sysv4 | sysv4.2uw2* | sysv4.3*)
wl='-Wl,'
;;
sysv4*MP*)
;;
sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
wl='-Wl,'
;;
unicos*)
wl='-Wl,'
;;
uts4*)
;;
esac
fi
# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
hardcode_libdir_flag_spec=
hardcode_libdir_separator=
hardcode_direct=no
hardcode_minus_L=no
case "$host_os" in
cygwin* | mingw* | pw32*)
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
if test "$GCC" != yes; then
with_gnu_ld=no
fi
;;
interix*)
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
openbsd*)
with_gnu_ld=no
;;
esac
ld_shlibs=yes
if test "$with_gnu_ld" = yes; then
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
# Unlike libtool, we use -rpath here, not --rpath, since the documented
# option of GNU ld is called -rpath, not --rpath.
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
case "$host_os" in
aix3* | aix4* | aix5*)
# On AIX/PPC, the GNU linker is very broken
if test "$host_cpu" != ia64; then
ld_shlibs=no
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports
# that the semantics of dynamic libraries on AmigaOS, at least up
# to version 4, is to share data among multiple programs linked
# with the same dynamic library. Since this doesn't match the
# behavior of shared libraries on other platforms, we cannot use
# them.
ld_shlibs=no
;;
beos*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
cygwin* | mingw* | pw32*)
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
interix[3-9]*)
hardcode_direct=no
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
gnu* | linux* | k*bsd*-gnu)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
netbsd*)
;;
solaris*)
if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then
ld_shlibs=no
elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
case `$LD -v 2>&1` in
*\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
ld_shlibs=no
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`'
else
ld_shlibs=no
fi
;;
esac
;;
sunos4*)
hardcode_direct=yes
;;
*)
if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then
:
else
ld_shlibs=no
fi
;;
esac
if test "$ld_shlibs" = no; then
hardcode_libdir_flag_spec=
fi
else
case "$host_os" in
aix3*)
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
if test "$GCC" = yes; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
fi
;;
aix4* | aix5*)
if test "$host_cpu" = ia64; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
# need to do runtime linking.
case $host_os in aix4.[23]|aix4.[23].*|aix5*)
for ld_flag in $LDFLAGS; do
if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
aix_use_runtimelinking=yes
break
fi
done
;;
esac
fi
hardcode_direct=yes
hardcode_libdir_separator=':'
if test "$GCC" = yes; then
case $host_os in aix4.[012]|aix4.[012].*)
collect2name=`${CC} -print-prog-name=collect2`
if test -f "$collect2name" && \
strings "$collect2name" | grep resolve_lib_name >/dev/null
then
# We have reworked collect2
:
else
# We have old collect2
hardcode_direct=unsupported
hardcode_minus_L=yes
hardcode_libdir_flag_spec='-L$libdir'
hardcode_libdir_separator=
fi
;;
esac
fi
# Begin _LT_AC_SYS_LIBPATH_AIX.
echo 'int main () { return 0; }' > conftest.c
${CC} ${LDFLAGS} conftest.c -o conftest
aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
if test -z "$aix_libpath"; then
aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; }
}'`
fi
if test -z "$aix_libpath"; then
aix_libpath="/usr/lib:/lib"
fi
rm -f conftest.c conftest
# End _LT_AC_SYS_LIBPATH_AIX.
if test "$aix_use_runtimelinking" = yes; then
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
else
if test "$host_cpu" = ia64; then
hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
else
hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
fi
fi
;;
amigaos*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
# see comment about different semantics on the GNU ld section
ld_shlibs=no
;;
bsdi[45]*)
;;
cygwin* | mingw* | pw32*)
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
# hardcode_libdir_flag_spec is actually meaningless, as there is
# no search path for DLLs.
hardcode_libdir_flag_spec=' '
libext=lib
;;
darwin* | rhapsody*)
hardcode_direct=no
if test "$GCC" = yes ; then
:
else
case $cc_basename in
xlc*)
;;
*)
ld_shlibs=no
;;
esac
fi
;;
dgux*)
hardcode_libdir_flag_spec='-L$libdir'
;;
freebsd1*)
ld_shlibs=no
;;
freebsd2.2*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
freebsd2*)
hardcode_direct=yes
hardcode_minus_L=yes
;;
freebsd* | dragonfly*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
hpux9*)
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
hpux10*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
fi
;;
hpux11*)
if test "$with_gnu_ld" = no; then
hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
hardcode_libdir_separator=:
case $host_cpu in
hppa*64*|ia64*)
hardcode_direct=no
;;
*)
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
;;
esac
fi
;;
irix5* | irix6* | nonstopux*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
netbsd*)
hardcode_libdir_flag_spec='-R$libdir'
hardcode_direct=yes
;;
newsos6)
hardcode_direct=yes
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
openbsd*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
else
case "$host_os" in
openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
hardcode_libdir_flag_spec='-R$libdir'
;;
*)
hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
;;
esac
fi
else
ld_shlibs=no
fi
;;
os2*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
;;
osf3*)
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*)
if test "$GCC" = yes; then
hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
else
# Both cc and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
fi
hardcode_libdir_separator=:
;;
solaris*)
hardcode_libdir_flag_spec='-R$libdir'
;;
sunos4*)
hardcode_libdir_flag_spec='-L$libdir'
hardcode_direct=yes
hardcode_minus_L=yes
;;
sysv4)
case $host_vendor in
sni)
hardcode_direct=yes # is this really true???
;;
siemens)
hardcode_direct=no
;;
motorola)
hardcode_direct=no #Motorola manual says yes, but my tests say they lie
;;
esac
;;
sysv4.3*)
;;
sysv4*MP*)
if test -d /usr/nec; then
ld_shlibs=yes
fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
;;
sysv5* | sco3.2v5* | sco5v6*)
hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`'
hardcode_libdir_separator=':'
;;
uts4*)
hardcode_libdir_flag_spec='-L$libdir'
;;
*)
ld_shlibs=no
;;
esac
fi
# Check dynamic linker characteristics
# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
# only about the one the linker finds when passed -lNAME. This is the last
# element of library_names_spec in libtool.m4, or possibly two of them if the
# linker has special search rules.
library_names_spec= # the last element of library_names_spec in libtool.m4
libname_spec='lib$name'
case "$host_os" in
aix3*)
library_names_spec='$libname.a'
;;
aix4* | aix5*)
library_names_spec='$libname$shrext'
;;
amigaos*)
library_names_spec='$libname.a'
;;
beos*)
library_names_spec='$libname$shrext'
;;
bsdi[45]*)
library_names_spec='$libname$shrext'
;;
cygwin* | mingw* | pw32*)
shrext=.dll
library_names_spec='$libname.dll.a $libname.lib'
;;
darwin* | rhapsody*)
shrext=.dylib
library_names_spec='$libname$shrext'
;;
dgux*)
library_names_spec='$libname$shrext'
;;
freebsd1*)
;;
freebsd* | dragonfly*)
case "$host_os" in
freebsd[123]*)
library_names_spec='$libname$shrext$versuffix' ;;
*)
library_names_spec='$libname$shrext' ;;
esac
;;
gnu*)
library_names_spec='$libname$shrext'
;;
hpux9* | hpux10* | hpux11*)
case $host_cpu in
ia64*)
shrext=.so
;;
hppa*64*)
shrext=.sl
;;
*)
shrext=.sl
;;
esac
library_names_spec='$libname$shrext'
;;
interix[3-9]*)
library_names_spec='$libname$shrext'
;;
irix5* | irix6* | nonstopux*)
library_names_spec='$libname$shrext'
case "$host_os" in
irix5* | nonstopux*)
libsuff= shlibsuff=
;;
*)
case $LD in
*-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;;
*-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;;
*-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;;
*) libsuff= shlibsuff= ;;
esac
;;
esac
;;
linux*oldld* | linux*aout* | linux*coff*)
;;
linux* | k*bsd*-gnu)
library_names_spec='$libname$shrext'
;;
knetbsd*-gnu)
library_names_spec='$libname$shrext'
;;
netbsd*)
library_names_spec='$libname$shrext'
;;
newsos6)
library_names_spec='$libname$shrext'
;;
nto-qnx*)
library_names_spec='$libname$shrext'
;;
openbsd*)
library_names_spec='$libname$shrext$versuffix'
;;
os2*)
libname_spec='$name'
shrext=.dll
library_names_spec='$libname.a'
;;
osf3* | osf4* | osf5*)
library_names_spec='$libname$shrext'
;;
rdos*)
;;
solaris*)
library_names_spec='$libname$shrext'
;;
sunos4*)
library_names_spec='$libname$shrext$versuffix'
;;
sysv4 | sysv4.3*)
library_names_spec='$libname$shrext'
;;
sysv4*MP*)
library_names_spec='$libname$shrext'
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
library_names_spec='$libname$shrext'
;;
uts4*)
library_names_spec='$libname$shrext'
;;
esac
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
# How to pass a linker flag through the compiler.
wl="$escaped_wl"
# Static library suffix (normally "a").
libext="$libext"
# Shared library suffix (normally "so").
shlibext="$shlibext"
# Format of library name prefix.
libname_spec="$escaped_libname_spec"
# Library names that the linker finds when passed -lNAME.
library_names_spec="$escaped_library_names_spec"
# Flag to hardcode \$libdir into a binary during linking.
# This must work even if \$libdir does not exist.
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
# Whether we need a single -rpath flag with a separated argument.
hardcode_libdir_separator="$hardcode_libdir_separator"
# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the
# resulting binary.
hardcode_direct="$hardcode_direct"
# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
# resulting binary.
hardcode_minus_L="$hardcode_minus_L"
EOF

1790
scripts/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

15
scripts/config/.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
*.o
conf*
!conf*.c
!conf*.h
mconf*
!mconf*.c
!mconf*.h
mconf_check
*.*.c
qconf*
qconf*.moc
!qconf*.cc
!qconf*.h
!images*.c
.tmp_qtcheck

107
scripts/config/Makefile Normal file
View File

@@ -0,0 +1,107 @@
# ===========================================================================
# OpenWrt configuration targets
# These targets are used from top-level makefile
# ===========================================================================
# Shared Makefile for the various kconfig executables:
# conf: Used for defconfig, oldconfig and related targets
# mconf: Used for the mconfig target.
# Utilizes the lxdialog package
# qconf: Used for the xconfig target
# Based on Qt which needs to be installed to compile it
# object files used by all kconfig flavours
# Platform specific fixes
#
# FreeBSD
check_lxdialog = $(shell $(SHELL) $(CURDIR)/lxdialog/check-lxdialog.sh -$(1))
export CFLAGS += -DKBUILD_NO_NLS -I. $(call check_lxdialog,ccflags)
export CXXFLAGS += -DKBUILD_NO_NLS
conf-objs := conf.o zconf.tab.o
mconf-objs := mconf.o zconf.tab.o
qconf-cxxobjs := qconf.o
qconf-objs := zconf.tab.o
lxdialog-objs := \
lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o \
lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
clean-files := zconf.tab.c zconf.lex.c zconf.hash.c
# Remove qconf junk files
clean-files += $(qconf-cxxobjs) qconf.moc .tmp_qtcheck qconf
all: conf mconf
conf: $(conf-objs)
mconf: $(mconf-objs) $(lxdialog-objs)
$(CC) -o $@ $^ $(call check_lxdialog,ldflags $(CC))
qconf: $(qconf-cxxobjs) $(qconf-objs)
ifneq ($(DISTRO-PKG-CONFIG),)
$(CXX) -o $@ $^ $(HOSTLOADLIBES_qconf)
else
echo "You don't have 'pkg-config' installed. Cannot continue"
echo "For now, you may use 'make menuconfig' instead of 'make xconfig'"
endif
clean:
rm -f *.o lxdialog/*.o $(clean-files) conf mconf
zconf.tab.o: zconf.lex.c zconf.hash.c confdata.c
kconfig_load.o: lkc_defs.h
zconf.tab.c: zconf.y $(wildcard zconf.tab.c_shipped)
zconf.lex.c: zconf.l $(wildcard zconf.lex.c_shipped)
zconf.hash.c: zconf.gperf $(wildcard zconf.hash.c_shipped)
%.tab.c: %.y
cp $@_shipped $@ || bison -l -b $* -p $(notdir $*) $<
%.lex.c: %.l
cp $@_shipped $@ || flex -L -P$(notdir $*) -o$@ $<
%.hash.c: %.gperf
cp $@_shipped $@ || gperf < $< > $@
ifeq ($(MAKECMDGOALS),qconf)
qconf.o: .tmp_qtcheck
.tmp_qtcheck: Makefile
-include .tmp_qtcheck
# Qt needs some extra effort...
.tmp_qtcheck:
@set -e; echo " CHECK qt"; \
if $(DISTRO-PKG-CONFIG) --exists Qt5Core; then \
cflags="-std=c++11 -fPIC `$(DISTRO-PKG-CONFIG) --cflags Qt5Core Qt5Gui Qt5Widgets`"; \
libs=`$(DISTRO-PKG-CONFIG) --libs Qt5Core Qt5Gui Qt5Widgets`; \
moc=`$(DISTRO-PKG-CONFIG) --variable=host_bins Qt5Core`/moc; \
elif $(DISTRO-PKG-CONFIG) --exists QtCore; then \
cflags=`$(DISTRO-PKG-CONFIG) --cflags QtCore QtGui`; \
libs=`$(DISTRO-PKG-CONFIG) --libs QtCore QtGui`; \
moc=`$(DISTRO-PKG-CONFIG) --variable=moc_location QtCore`; \
else \
echo >&2 "*"; \
echo >&2 "* Could not find Qt via $(DISTRO-PKG-CONFIG)."; \
echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"; \
echo >&2 "*"; \
exit 1; \
fi; \
echo "KC_QT_CFLAGS=$$cflags" > $@; \
echo "KC_QT_LIBS=$$libs" >> $@; \
echo "KC_QT_MOC=$$moc" >> $@
endif
#Define compiler flags to build qconf
HOSTLOADLIBES_qconf = $(KC_QT_LIBS)
HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS)
qconf.o: qconf.moc
qconf.o: CXXFLAGS+=$(HOSTCXXFLAGS_qconf.o)
moc = $(KC_QT_MOC) -i $< -o $@
%.moc: %.h .tmp_qtcheck
$(call moc)

2
scripts/config/README Normal file
View File

@@ -0,0 +1,2 @@
These files were taken from the Linux 3.9 Kernel
Configuration System and modified for the OpenWrt Buildroot.

703
scripts/config/conf.c Normal file
View File

@@ -0,0 +1,703 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <locale.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include "lkc.h"
static void conf(struct menu *menu);
static void check_conf(struct menu *menu);
static void xfgets(char *str, int size, FILE *in);
enum input_mode {
oldaskconfig,
silentoldconfig,
oldconfig,
allnoconfig,
allyesconfig,
allmodconfig,
alldefconfig,
randconfig,
defconfig,
savedefconfig,
listnewconfig,
olddefconfig,
} input_mode = oldaskconfig;
static int indent = 1;
static int tty_stdio;
static int valid_stdin = 1;
static int sync_kconfig;
static int conf_cnt;
static char line[PATH_MAX];
static struct menu *rootEntry;
static void print_help(struct menu *menu)
{
struct gstr help = str_new();
menu_get_ext_help(menu, &help);
printf("\n%s\n", str_get(&help));
str_free(&help);
}
static void strip(char *str)
{
char *p = str;
int l;
while ((isspace(*p)))
p++;
l = strlen(p);
if (p != str)
memmove(str, p, l + 1);
if (!l)
return;
p = str + l - 1;
while ((isspace(*p)))
*p-- = 0;
}
static void check_stdin(void)
{
if (!valid_stdin) {
printf("%s",_("aborted!\n\n"));
printf("%s",_("Console input/output is redirected. "));
printf("%s",_("Run 'make oldconfig' to update configuration.\n\n"));
exit(1);
}
}
static int conf_askvalue(struct symbol *sym, const char *def)
{
enum symbol_type type = sym_get_type(sym);
if (!sym_has_value(sym))
printf("%s",_("(NEW) "));
line[0] = '\n';
line[1] = 0;
if (!sym_is_changable(sym)) {
printf("%s\n", def);
line[0] = '\n';
line[1] = 0;
return 0;
}
switch (input_mode) {
case oldconfig:
case silentoldconfig:
if (sym_has_value(sym)) {
printf("%s\n", def);
return 0;
}
check_stdin();
/* fall through */
case oldaskconfig:
fflush(stdout);
xfgets(line, sizeof(line), stdin);
if (!tty_stdio)
printf("\n");
return 1;
default:
break;
}
switch (type) {
case S_INT:
case S_HEX:
case S_STRING:
printf("%s\n", def);
return 1;
default:
;
}
printf("%s", line);
return 1;
}
static int conf_string(struct menu *menu)
{
struct symbol *sym = menu->sym;
const char *def;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
printf("(%s) ", sym->name);
def = sym_get_string_value(sym);
if (sym_get_string_value(sym))
printf("[%s] ", def);
if (!conf_askvalue(sym, def))
return 0;
switch (line[0]) {
case '\n':
break;
case '?':
/* print help */
if (line[1] == '\n') {
print_help(menu);
def = NULL;
break;
}
/* fall through */
default:
line[strlen(line)-1] = 0;
def = line;
}
if (def && sym_set_string_value(sym, def))
return 0;
}
}
static int conf_sym(struct menu *menu)
{
struct symbol *sym = menu->sym;
tristate oldval, newval;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
if (sym->name)
printf("(%s) ", sym->name);
putchar('[');
oldval = sym_get_tristate_value(sym);
switch (oldval) {
case no:
putchar('N');
break;
case mod:
putchar('M');
break;
case yes:
putchar('Y');
break;
}
if (oldval != no && sym_tristate_within_range(sym, no))
printf("/n");
if (oldval != mod && sym_tristate_within_range(sym, mod))
printf("/m");
if (oldval != yes && sym_tristate_within_range(sym, yes))
printf("/y");
if (menu_has_help(menu))
printf("/?");
printf("] ");
if (!conf_askvalue(sym, sym_get_string_value(sym)))
return 0;
strip(line);
switch (line[0]) {
case 'n':
case 'N':
newval = no;
if (!line[1] || !strcmp(&line[1], "o"))
break;
continue;
case 'm':
case 'M':
newval = mod;
if (!line[1])
break;
continue;
case 'y':
case 'Y':
newval = yes;
if (!line[1] || !strcmp(&line[1], "es"))
break;
continue;
case 0:
newval = oldval;
break;
case '?':
goto help;
default:
continue;
}
if (sym_set_tristate_value(sym, newval))
return 0;
help:
print_help(menu);
}
}
static int conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct menu *child;
bool is_new;
sym = menu->sym;
is_new = !sym_has_value(sym);
if (sym_is_changable(sym)) {
conf_sym(menu);
sym_calc_value(sym);
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
return 0;
case yes:
break;
}
} else {
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
return 0;
case yes:
break;
}
}
while (1) {
int cnt, def;
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
def_sym = sym_get_choice_value(sym);
cnt = def = 0;
line[0] = 0;
for (child = menu->list; child; child = child->next) {
if (!menu_is_visible(child))
continue;
if (!child->sym) {
printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
continue;
}
cnt++;
if (child->sym == def_sym) {
def = cnt;
printf("%*c", indent, '>');
} else
printf("%*c", indent, ' ');
printf(" %d. %s", cnt, _(menu_get_prompt(child)));
if (child->sym->name)
printf(" (%s)", child->sym->name);
if (!sym_has_value(child->sym))
printf("%s",_(" (NEW)"));
printf("\n");
}
printf(_("%*schoice"), indent - 1, "");
if (cnt == 1) {
printf("[1]: 1\n");
goto conf_childs;
}
printf("[1-%d", cnt);
if (menu_has_help(menu))
printf("?");
printf("]: ");
switch (input_mode) {
case oldconfig:
case silentoldconfig:
if (!is_new) {
cnt = def;
printf("%d\n", cnt);
break;
}
check_stdin();
/* fall through */
case oldaskconfig:
fflush(stdout);
xfgets(line, sizeof(line), stdin);
strip(line);
if (line[0] == '?') {
print_help(menu);
continue;
}
if (!line[0])
cnt = def;
else if (isdigit(line[0]))
cnt = atoi(line);
else
continue;
break;
default:
break;
}
conf_childs:
for (child = menu->list; child; child = child->next) {
if (!child->sym || !menu_is_visible(child))
continue;
if (!--cnt)
break;
}
if (!child)
continue;
if (line[0] && line[strlen(line) - 1] == '?') {
print_help(child);
continue;
}
sym_set_choice_value(sym, child->sym);
for (child = child->list; child; child = child->next) {
indent += 2;
conf(child);
indent -= 2;
}
return 1;
}
}
static void conf(struct menu *menu)
{
struct symbol *sym;
struct property *prop;
struct menu *child;
if (!menu_is_visible(menu))
return;
sym = menu->sym;
prop = menu->prompt;
if (prop) {
const char *prompt;
switch (prop->type) {
case P_MENU:
if ((input_mode == silentoldconfig ||
input_mode == listnewconfig ||
input_mode == olddefconfig) &&
rootEntry != menu) {
check_conf(menu);
return;
}
/* fall through */
case P_COMMENT:
prompt = menu_get_prompt(menu);
if (prompt)
printf("%*c\n%*c %s\n%*c\n",
indent, '*',
indent, '*', _(prompt),
indent, '*');
default:
;
}
}
if (!sym)
goto conf_childs;
if (sym_is_choice(sym)) {
conf_choice(menu);
if (sym->curr.tri != mod)
return;
goto conf_childs;
}
switch (sym->type) {
case S_INT:
case S_HEX:
case S_STRING:
conf_string(menu);
break;
default:
conf_sym(menu);
break;
}
conf_childs:
if (sym)
indent += 2;
for (child = menu->list; child; child = child->next)
conf(child);
if (sym)
indent -= 2;
}
static void check_conf(struct menu *menu)
{
struct symbol *sym;
struct menu *child;
if (!menu_is_visible(menu))
return;
sym = menu->sym;
if (sym && !sym_has_value(sym)) {
if (sym_is_changable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
if (input_mode == listnewconfig) {
if (sym->name && !sym_is_choice_value(sym)) {
printf("%s%s\n", CONFIG_, sym->name);
}
} else if (input_mode != olddefconfig) {
if (!conf_cnt++)
printf("%s",_("*\n* Restart config...\n*\n"));
rootEntry = menu_get_parent_menu(menu);
conf(rootEntry);
}
}
}
for (child = menu->list; child; child = child->next)
check_conf(child);
}
static struct option long_opts[] = {
{"oldaskconfig", no_argument, NULL, oldaskconfig},
{"oldconfig", no_argument, NULL, oldconfig},
{"silentoldconfig", no_argument, NULL, silentoldconfig},
{"defconfig", optional_argument, NULL, defconfig},
{"savedefconfig", required_argument, NULL, savedefconfig},
{"allnoconfig", no_argument, NULL, allnoconfig},
{"allyesconfig", no_argument, NULL, allyesconfig},
{"allmodconfig", no_argument, NULL, allmodconfig},
{"alldefconfig", no_argument, NULL, alldefconfig},
{"randconfig", no_argument, NULL, randconfig},
{"listnewconfig", no_argument, NULL, listnewconfig},
{"olddefconfig", no_argument, NULL, olddefconfig},
/*
* oldnoconfig is an alias of olddefconfig, because people already
* are dependent on its behavior(sets new symbols to their default
* value but not 'n') with the counter-intuitive name.
*/
{"oldnoconfig", no_argument, NULL, olddefconfig},
{NULL, 0, NULL, 0}
};
static void conf_usage(const char *progname)
{
printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
printf("[option] is _one_ of the following:\n");
printf(" --listnewconfig List new options\n");
printf(" --oldaskconfig Start a new configuration using a line-oriented program\n");
printf(" --oldconfig Update a configuration using a provided .config as base\n");
printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n");
printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n");
printf(" --oldnoconfig An alias of olddefconfig\n");
printf(" --defconfig <file> New config with default defined in <file>\n");
printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n");
printf(" --allnoconfig New config where all options are answered with no\n");
printf(" --allyesconfig New config where all options are answered with yes\n");
printf(" --allmodconfig New config where all options are answered with mod\n");
printf(" --alldefconfig New config with all symbols set to default\n");
printf(" --randconfig New config with random answer to all options\n");
}
int main(int ac, char **av)
{
const char *progname = av[0];
int opt;
const char *name, *defconfig_file = NULL /* gcc uninit */;
struct stat tmpstat;
const char *input_file = NULL, *output_file = NULL;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
tty_stdio = isatty(0) && isatty(1) && isatty(2);
while ((opt = getopt_long(ac, av, "r:w:s", long_opts, NULL)) != -1) {
if (opt == 's') {
conf_set_message_callback(NULL);
continue;
}
switch (opt) {
case silentoldconfig:
sync_kconfig = 1;
break;
case defconfig:
case savedefconfig:
defconfig_file = optarg;
break;
case randconfig:
{
struct timeval now;
unsigned int seed;
char *seed_env;
/*
* Use microseconds derived seed,
* compensate for systems where it may be zero
*/
gettimeofday(&now, NULL);
seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
seed_env = getenv("KCONFIG_SEED");
if( seed_env && *seed_env ) {
char *endp;
int tmp = (int)strtol(seed_env, &endp, 0);
if (*endp == '\0') {
seed = tmp;
}
}
fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
srand(seed);
break;
}
case oldaskconfig:
case oldconfig:
case allnoconfig:
case allyesconfig:
case allmodconfig:
case alldefconfig:
case listnewconfig:
case olddefconfig:
break;
case 'r':
input_file = optarg;
continue;
case 'w':
output_file = optarg;
continue;
case '?':
conf_usage(progname);
exit(1);
break;
}
input_mode = (enum input_mode)opt;
}
if (ac == optind) {
printf(_("%s: Kconfig file missing\n"), av[0]);
conf_usage(progname);
exit(1);
}
name = av[optind];
conf_parse(name);
//zconfdump(stdout);
if (sync_kconfig) {
name = conf_get_configname();
if (stat(name, &tmpstat)) {
fprintf(stderr, _("***\n"
"*** Configuration file \"%s\" not found!\n"
"***\n"
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
"*** \"make menuconfig\" or \"make xconfig\").\n"
"***\n"), name);
exit(1);
}
}
switch (input_mode) {
case defconfig:
if (!defconfig_file)
defconfig_file = conf_get_default_confname();
if (conf_read(defconfig_file)) {
printf(_("***\n"
"*** Can't find default configuration \"%s\"!\n"
"***\n"), defconfig_file);
exit(1);
}
break;
case savedefconfig:
case silentoldconfig:
case oldaskconfig:
case oldconfig:
case listnewconfig:
case olddefconfig:
case allnoconfig:
case allyesconfig:
case allmodconfig:
case alldefconfig:
case randconfig:
conf_read(input_file);
break;
default:
break;
}
if (sync_kconfig) {
if (conf_get_changed()) {
name = getenv("KCONFIG_NOSILENTUPDATE");
if (name && *name) {
fprintf(stderr,
_("\n*** The configuration requires explicit update.\n\n"));
return 1;
}
}
valid_stdin = tty_stdio;
}
switch (input_mode) {
case allnoconfig:
conf_set_all_new_symbols(def_no);
break;
case allyesconfig:
conf_set_all_new_symbols(def_yes);
break;
case allmodconfig:
conf_set_all_new_symbols(def_mod);
break;
case alldefconfig:
conf_set_all_new_symbols(def_default);
break;
case randconfig:
/* Really nothing to do in this loop */
while (conf_set_all_new_symbols(def_random)) ;
break;
case defconfig:
conf_set_all_new_symbols(def_default);
break;
case savedefconfig:
break;
case oldaskconfig:
rootEntry = &rootmenu;
conf(&rootmenu);
input_mode = silentoldconfig;
/* fall through */
case oldconfig:
case listnewconfig:
case olddefconfig:
case silentoldconfig:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
} while (conf_cnt &&
(input_mode != listnewconfig &&
input_mode != olddefconfig));
break;
}
if (sync_kconfig) {
/* silentoldconfig is used during the build so we shall update autoconf.
* All other commands are only used to generate a config.
*/
if ((output_file || conf_get_changed()) &&
conf_write(output_file)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
if (conf_write_autoconf()) {
fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
return 1;
}
} else if (input_mode == savedefconfig) {
if (conf_write_defconfig(defconfig_file)) {
fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
defconfig_file);
return 1;
}
} else if (input_mode != listnewconfig) {
if (conf_write(output_file)) {
fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
exit(1);
}
}
return 0;
}
/*
* Helper function to facilitate fgets() by Jean Sacren.
*/
void xfgets(char *str, int size, FILE *in)
{
if (fgets(str, size, in) == NULL)
fprintf(stderr, "\nError in reading or end of file.\n");
}

1252
scripts/config/confdata.c Normal file

File diff suppressed because it is too large Load Diff

1209
scripts/config/expr.c Normal file

File diff suppressed because it is too large Load Diff

239
scripts/config/expr.h Normal file
View File

@@ -0,0 +1,239 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#ifndef EXPR_H
#define EXPR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <assert.h>
#include <stdio.h>
#include "list.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
struct file {
struct file *next;
struct file *parent;
const char *name;
int lineno;
};
typedef enum tristate {
no, mod, yes
} tristate;
enum expr_type {
E_NONE, E_OR, E_AND, E_NOT,
E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
E_LIST, E_SYMBOL, E_RANGE
};
union expr_data {
struct expr *expr;
struct symbol *sym;
};
struct expr {
enum expr_type type;
union expr_data left, right;
};
#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
#define EXPR_NOT(dep) (2-(dep))
#define expr_list_for_each_sym(l, e, s) \
for (e = (l); e && (s = e->right.sym); e = e->left.expr)
struct expr_value {
struct expr *expr;
tristate tri;
};
struct symbol_value {
void *val;
tristate tri;
};
enum symbol_type {
S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
};
/* enum values are used as index to symbol.def[] */
enum {
S_DEF_USER, /* main user value */
S_DEF_AUTO, /* values read from auto.conf */
S_DEF_DEF3, /* Reserved for UI usage */
S_DEF_DEF4, /* Reserved for UI usage */
S_DEF_COUNT
};
struct symbol {
struct symbol *next;
char *name;
enum symbol_type type;
struct symbol_value curr;
struct symbol_value def[S_DEF_COUNT];
tristate visible;
int flags;
struct property *prop;
struct expr_value dir_dep;
struct expr_value rev_dep;
};
#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
#define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
#define SYMBOL_CHANGED 0x0400 /* ? */
#define SYMBOL_AUTO 0x1000 /* value from environment variable */
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
/* Set when symbol.def[] is used */
#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
/* choice values need to be set before calculating this symbol value */
#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000
/* Set symbol to y if allnoconfig; used for symbols that hide others */
#define SYMBOL_ALLNOCONFIG_Y 0x200000
#define SYMBOL_MAXLENGTH 256
#define SYMBOL_HASHSIZE 9973
/* A property represent the config options that can be associated
* with a config "symbol".
* Sample:
* config FOO
* default y
* prompt "foo prompt"
* select BAR
* config BAZ
* int "BAZ Value"
* range 1..255
*/
enum prop_type {
P_UNKNOWN,
P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
P_COMMENT, /* text associated with a comment */
P_MENU, /* prompt associated with a menuconfig option */
P_DEFAULT, /* default y */
P_CHOICE, /* choice value */
P_SELECT, /* select BAR */
P_RANGE, /* range 7..100 (for a symbol) */
P_ENV, /* value from environment variable */
P_SYMBOL, /* where a symbol is defined */
P_RESET, /* reset to defaults condition */
};
struct property {
struct property *next; /* next property - null if last */
struct symbol *sym; /* the symbol for which the property is associated */
enum prop_type type; /* type of property */
const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
struct expr_value visible;
struct expr *expr; /* the optional conditional part of the property */
struct menu *menu; /* the menu the property are associated with
* valid for: P_SELECT, P_RANGE, P_CHOICE,
* P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
struct file *file; /* what file was this property defined */
int lineno; /* what lineno was this property defined */
};
#define for_all_properties(sym, st, tok) \
for (st = sym->prop; st; st = st->next) \
if (st->type == (tok))
#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
#define for_all_prompts(sym, st) \
for (st = sym->prop; st; st = st->next) \
if (st->text)
struct menu {
struct menu *next;
struct menu *parent;
struct menu *list;
struct symbol *sym;
struct property *prompt;
struct expr *visibility;
struct expr *dep;
unsigned int flags;
char *help;
struct file *file;
int lineno;
void *data;
};
#define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
struct jump_key {
struct list_head entries;
size_t offset;
struct menu *target;
int index;
};
#define JUMP_NB 9
extern struct file *file_list;
extern struct file *current_file;
struct file *lookup_file(const char *name);
extern struct symbol symbol_yes, symbol_no, symbol_mod;
extern struct symbol *modules_sym;
extern struct symbol *sym_defconfig_list;
extern int cdebug;
struct expr *expr_alloc_symbol(struct symbol *sym);
struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
struct expr *expr_copy(const struct expr *org);
void expr_free(struct expr *e);
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
tristate expr_calc_value(struct expr *e);
struct expr *expr_trans_bool(struct expr *e);
struct expr *expr_eliminate_dups(struct expr *e);
struct expr *expr_transform(struct expr *e);
int expr_contains_symbol(struct expr *dep, struct symbol *sym);
bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
void expr_fprint(struct expr *e, FILE *out);
struct gstr; /* forward */
void expr_gstr_print(struct expr *e, struct gstr *gs);
static inline int expr_is_yes(struct expr *e)
{
return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
}
static inline int expr_is_no(struct expr *e)
{
return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
}
#ifdef __cplusplus
}
#endif
#endif /* EXPR_H */

326
scripts/config/images.c Normal file
View File

@@ -0,0 +1,326 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
static const char *xpm_load[] = {
"22 22 5 1",
". c None",
"# c #000000",
"c c #838100",
"a c #ffff00",
"b c #ffffff",
"......................",
"......................",
"......................",
"............####....#.",
"...........#....##.##.",
"..................###.",
".................####.",
".####...........#####.",
"#abab##########.......",
"#babababababab#.......",
"#ababababababa#.......",
"#babababababab#.......",
"#ababab###############",
"#babab##cccccccccccc##",
"#abab##cccccccccccc##.",
"#bab##cccccccccccc##..",
"#ab##cccccccccccc##...",
"#b##cccccccccccc##....",
"###cccccccccccc##.....",
"##cccccccccccc##......",
"###############.......",
"......................"};
static const char *xpm_save[] = {
"22 22 5 1",
". c None",
"# c #000000",
"a c #838100",
"b c #c5c2c5",
"c c #cdb6d5",
"......................",
".####################.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbbbb#bb#.",
".#aa#bbbbbbbbbcbb####.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbccbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aa#bbbbbbbbbbbb#aa#.",
".#aaa############aaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaaaaaaaaaaaaaaaaa#.",
".#aaa#############aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
".#aaa#########bbb#aa#.",
"..##################..",
"......................"};
static const char *xpm_back[] = {
"22 22 3 1",
". c None",
"# c #000083",
"a c #838183",
"......................",
"......................",
"......................",
"......................",
"......................",
"...........######a....",
"..#......##########...",
"..##...####......##a..",
"..###.###.........##..",
"..######..........##..",
"..#####...........##..",
"..######..........##..",
"..#######.........##..",
"..########.......##a..",
"...............a###...",
"...............###....",
"......................",
"......................",
"......................",
"......................",
"......................",
"......................"};
static const char *xpm_tree_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......#...............",
"......########........",
"......................",
"......................"};
static const char *xpm_single_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"..........#...........",
"......................",
"......................"};
static const char *xpm_split_view[] = {
"22 22 2 1",
". c None",
"# c #000000",
"......................",
"......................",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......#......#........",
"......................",
"......................"};
static const char *xpm_symbol_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .......... ",
" "};
static const char *xpm_symbol_mod[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" . . ",
" .......... ",
" "};
static const char *xpm_symbol_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . . ",
" . . . ",
" . .. . ",
" . . .. . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_choice_no[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" .... ",
" "};
static const char *xpm_choice_yes[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .... ",
" .. .. ",
" . . ",
" . .. . ",
" . .... . ",
" . .... . ",
" . .. . ",
" . . ",
" .. .. ",
" .... ",
" "};
static const char *xpm_menu[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_menu_inv[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" .......... ",
" .. ...... ",
" .. .... ",
" .. .. ",
" .. .. ",
" .. .... ",
" .. ...... ",
" .......... ",
" .......... ",
" "};
static const char *xpm_menuback[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" .......... ",
" . . ",
" . .. . ",
" . .... . ",
" . ...... . ",
" . ...... . ",
" . .... . ",
" . .. . ",
" . . ",
" .......... ",
" "};
static const char *xpm_void[] = {
"12 12 2 1",
" c white",
". c black",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" "};

131
scripts/config/list.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef LIST_H
#define LIST_H
/*
* Copied from include/linux/...
*/
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *_new,
struct list_head *prev,
struct list_head *next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *_new, struct list_head *head)
{
__list_add(_new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (struct list_head*)LIST_POISON1;
entry->prev = (struct list_head*)LIST_POISON2;
}
#endif

187
scripts/config/lkc.h Normal file
View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#ifndef LKC_H
#define LKC_H
#include "expr.h"
#ifndef KBUILD_NO_NLS
# include <libintl.h>
#else
static inline const char *gettext(const char *txt) { return txt; }
static inline void textdomain(const char *domainname) {}
static inline void bindtextdomain(const char *name, const char *dir) {}
static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "lkc_proto.h"
#define SRCTREE "srctree"
#ifndef PACKAGE
#define PACKAGE "linux"
#endif
#define LOCALEDIR "/usr/share/locale"
#define _(text) gettext(text)
#define N_(text) (text)
#ifndef CONFIG_
#define CONFIG_ "CONFIG_"
#endif
static inline const char *CONFIG_prefix(void)
{
return getenv( "CONFIG_" ) ?: CONFIG_;
}
#undef CONFIG_
#define CONFIG_ CONFIG_prefix()
#define TF_COMMAND 0x0001
#define TF_PARAM 0x0002
#define TF_OPTION 0x0004
enum conf_def_mode {
def_default,
def_yes,
def_mod,
def_no,
def_random
};
#define T_OPT_MODULES 1
#define T_OPT_DEFCONFIG_LIST 2
#define T_OPT_ENV 3
#define T_OPT_ALLNOCONFIG_Y 4
struct kconf_id {
int name;
int token;
unsigned int flags;
enum symbol_type stype;
};
void zconfdump(FILE *out);
void zconf_starthelp(void);
FILE *zconf_fopen(const char *name);
void zconf_initscan(const char *name);
void zconf_nextfile(const char *name);
int zconf_lineno(void);
const char *zconf_curname(void);
/* confdata.c */
const char *conf_get_configname(void);
const char *conf_get_autoconfig_name(void);
char *conf_get_default_confname(void);
void sym_set_change_count(int count);
void sym_add_change_count(int count);
bool conf_set_all_new_symbols(enum conf_def_mode mode);
void set_all_choice_values(struct symbol *csym);
/* confdata.c and expr.c */
static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
{
assert(len != 0);
if (fwrite(str, len, count, out) != count)
fprintf(stderr, "Error in writing or end of file.\n");
}
/* menu.c */
void _menu_init(void);
void menu_warn(struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
void menu_add_entry(struct symbol *sym);
void menu_end_entry(void);
void menu_add_dep(struct expr *dep);
void menu_add_visibility(struct expr *dep);
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
void menu_add_option(int token, char *arg);
void menu_finalize(struct menu *parent);
void menu_set_type(int type);
/* util.c */
struct file *file_lookup(const char *name);
int file_write_dep(const char *name);
void *xmalloc(size_t size);
void *xcalloc(size_t nmemb, size_t size);
struct gstr {
size_t len;
char *s;
/*
* when max_width is not zero long lines in string s (if any) get
* wrapped not to exceed the max_width value
*/
int max_width;
};
struct gstr str_new(void);
void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...);
const char *str_get(struct gstr *gs);
/* symbol.c */
extern struct expr *sym_env_list;
void sym_init(void);
void sym_clear_all_valid(void);
struct symbol *sym_choice_default(struct symbol *sym);
const char *sym_get_string_default(struct symbol *sym);
struct symbol *sym_check_deps(struct symbol *sym);
struct property *prop_alloc(enum prop_type type, struct symbol *sym);
struct symbol *prop_get_symbol(struct property *prop);
struct property *sym_get_env_prop(struct symbol *sym);
static inline tristate sym_get_tristate_value(struct symbol *sym)
{
return sym->curr.tri;
}
static inline struct symbol *sym_get_choice_value(struct symbol *sym)
{
return (struct symbol *)sym->curr.val;
}
static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
{
return sym_set_tristate_value(chval, yes);
}
static inline bool sym_is_choice(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICE ? true : false;
}
static inline bool sym_is_choice_value(struct symbol *sym)
{
return sym->flags & SYMBOL_CHOICEVAL ? true : false;
}
static inline bool sym_is_optional(struct symbol *sym)
{
return sym->flags & SYMBOL_OPTIONAL ? true : false;
}
static inline bool sym_has_value(struct symbol *sym)
{
return sym->flags & SYMBOL_DEF_USER ? true : false;
}
#ifdef __cplusplus
}
#endif
#endif /* LKC_H */

View File

@@ -0,0 +1,53 @@
#include <stdarg.h>
/* confdata.c */
void conf_parse(const char *name);
int conf_read(const char *name);
int conf_read_simple(const char *name, int);
void conf_reset(int def);
int conf_write_defconfig(const char *name);
int conf_write(const char *name);
int conf_write_autoconf(void);
bool conf_get_changed(void);
void conf_set_changed_callback(void (*fn)(void));
void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap));
/* menu.c */
extern struct menu rootmenu;
bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu);
const char * menu_get_prompt(struct menu *menu);
struct menu * menu_get_root_menu(struct menu *menu);
struct menu * menu_get_parent_menu(struct menu *menu);
bool menu_has_help(struct menu *menu);
const char * menu_get_help(struct menu *menu);
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
void menu_get_ext_help(struct menu *menu, struct gstr *help);
/* symbol.c */
extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name);
const char * sym_expand_string_value(const char *in);
const char * sym_escape_string_value(const char *in);
struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym);
enum symbol_type sym_get_type(struct symbol *sym);
bool sym_tristate_within_range(struct symbol *sym,tristate tri);
bool sym_set_tristate_value(struct symbol *sym,tristate tri);
tristate sym_toggle_tristate_value(struct symbol *sym);
bool sym_string_valid(struct symbol *sym, const char *newval);
bool sym_string_within_range(struct symbol *sym, const char *str);
bool sym_set_string_value(struct symbol *sym, const char *newval);
bool sym_is_changable(struct symbol *sym);
struct property * sym_get_choice_prop(struct symbol *sym);
const char * sym_get_string_value(struct symbol *sym);
const char * prop_get_type_name(enum prop_type type);
/* expr.c */
void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken);

2
scripts/config/lxdialog/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
lxdialog
*.o

View File

@@ -0,0 +1,91 @@
#!/bin/sh
# Check ncurses compatibility
# What library to link
ldflags()
{
pkg-config --libs ncursesw 2>/dev/null && exit
pkg-config --libs ncurses 2>/dev/null && exit
for ext in so a dll.a dylib ; do
for lib in ncursesw ncurses curses ; do
$cc -print-file-name=lib${lib}.${ext} | grep -q /
if [ $? -eq 0 ]; then
echo "-l${lib}"
exit
fi
done
done
exit 1
}
# Where is ncurses.h?
ccflags()
{
if pkg-config --cflags ncursesw 2>/dev/null; then
echo '-DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1'
elif pkg-config --cflags ncurses 2>/dev/null; then
echo '-DCURSES_LOC="<ncurses.h>"'
elif [ -f /usr/include/ncursesw/curses.h ]; then
echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
echo ' -DNCURSES_WIDECHAR=1'
elif [ -f /usr/include/ncurses/ncurses.h ]; then
echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
elif [ -f /usr/include/ncurses/curses.h ]; then
echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
elif [ -f /usr/include/ncurses.h ]; then
echo '-DCURSES_LOC="<ncurses.h>"'
else
echo '-DCURSES_LOC="<curses.h>"'
fi
}
# Temp file, try to clean up after us
tmp=.lxdialog.tmp
trap "rm -f $tmp" 0 1 2 3 15
# Check if we can link to ncurses
check() {
$cc -x c - -o $tmp 2>/dev/null <<'EOF'
#include CURSES_LOC
main() {}
EOF
if [ $? != 0 ]; then
echo " *** Unable to find the ncurses libraries or the" 1>&2
echo " *** required header files." 1>&2
echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
echo " *** " 1>&2
echo " *** Install ncurses (ncurses-devel) and try again." 1>&2
echo " *** " 1>&2
exit 1
fi
}
usage() {
printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
}
if [ $# -eq 0 ]; then
usage
exit 1
fi
cc=""
case "$1" in
"-check")
shift
cc="$@"
check
;;
"-ccflags")
ccflags
;;
"-ldflags")
shift
cc="$@"
ldflags
;;
"*")
usage
exit 1
;;
esac

View File

@@ -0,0 +1,332 @@
/*
* checklist.c -- implements the checklist box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
* Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
static int list_width, check_x, item_x;
/*
* Print list item
*/
static void print_item(WINDOW * win, int choice, int selected)
{
int i;
char *list_item = malloc(list_width + 1);
strncpy(list_item, item_str(), list_width - item_x);
list_item[list_width - item_x] = '\0';
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
wmove(win, choice, 0);
for (i = 0; i < list_width; i++)
waddch(win, ' ');
wmove(win, choice, check_x);
wattrset(win, selected ? dlg.check_selected.atr
: dlg.check.atr);
if (!item_is_tag(':'))
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
mvwaddch(win, choice, item_x, list_item[0]);
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
waddstr(win, list_item + 1);
if (selected) {
wmove(win, choice, check_x + 1);
wrefresh(win);
}
free(list_item);
}
/*
* Print the scroll indicators.
*/
static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
int y, int x, int height)
{
wmove(win, y, x);
if (scroll > 0) {
wattrset(win, dlg.uarrow.atr);
waddch(win, ACS_UARROW);
waddstr(win, "(-)");
} else {
wattrset(win, dlg.menubox.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
y = y + height + 1;
wmove(win, y, x);
if ((height < item_no) && (scroll + choice < item_no - 1)) {
wattrset(win, dlg.darrow.atr);
waddch(win, ACS_DARROW);
waddstr(win, "(+)");
} else {
wattrset(win, dlg.menubox_border.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
}
/*
* Display the termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 11;
int y = height - 2;
print_button(dialog, gettext("Select"), y, x, selected == 0);
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
wmove(dialog, y, x + 1 + 14 * selected);
wrefresh(dialog);
}
/*
* Display a dialog box with a list of options that can be turned on or off
* in the style of radiolist (only one option turned on at a time).
*/
int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height)
{
int i, x, y, box_x, box_y;
int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
WINDOW *dialog, *list;
/* which item to highlight */
item_foreach() {
if (item_is_tag('X'))
choice = item_n();
if (item_is_selected()) {
choice = item_n();
break;
}
}
do_resize:
if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
max_choice = MIN(list_height, item_count());
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
list_width = width - 6;
box_y = height - list_height - 5;
box_x = (width - list_width) / 2 - 1;
/* create new window for the list */
list = subwin(dialog, list_height, list_width, y + box_y + 1,
x + box_x + 1);
keypad(list, TRUE);
/* draw a box around the list items */
draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
dlg.menubox_border.atr, dlg.menubox.atr);
/* Find length of longest item in order to center checklist */
check_x = 0;
item_foreach()
check_x = MAX(check_x, strlen(item_str()) + 4);
check_x = MIN(check_x, list_width);
check_x = (list_width - check_x) / 2;
item_x = check_x + 4;
if (choice >= list_height) {
scroll = choice - list_height + 1;
choice -= scroll;
}
/* Print the list */
for (i = 0; i < max_choice; i++) {
item_set(scroll + i);
print_item(list, i, i == choice);
}
print_arrows(dialog, choice, item_count(), scroll,
box_y, box_x + check_x + 5, list_height);
print_buttons(dialog, height, width, 0);
wnoutrefresh(dialog);
wnoutrefresh(list);
doupdate();
while (key != KEY_ESC) {
key = wgetch(dialog);
for (i = 0; i < max_choice; i++) {
item_set(i + scroll);
if (toupper(key) == toupper(item_str()[0]))
break;
}
if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
key == '+' || key == '-') {
if (key == KEY_UP || key == '-') {
if (!choice) {
if (!scroll)
continue;
/* Scroll list down */
if (list_height > 1) {
/* De-highlight current first item */
item_set(scroll);
print_item(list, 0, FALSE);
scrollok(list, TRUE);
wscrl(list, -1);
scrollok(list, FALSE);
}
scroll--;
item_set(scroll);
print_item(list, 0, TRUE);
print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
wrefresh(list);
continue; /* wait for another key press */
} else
i = choice - 1;
} else if (key == KEY_DOWN || key == '+') {
if (choice == max_choice - 1) {
if (scroll + choice >= item_count() - 1)
continue;
/* Scroll list up */
if (list_height > 1) {
/* De-highlight current last item before scrolling up */
item_set(scroll + max_choice - 1);
print_item(list,
max_choice - 1,
FALSE);
scrollok(list, TRUE);
wscrl(list, 1);
scrollok(list, FALSE);
}
scroll++;
item_set(scroll + max_choice - 1);
print_item(list, max_choice - 1, TRUE);
print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
wrefresh(list);
continue; /* wait for another key press */
} else
i = choice + 1;
}
if (i != choice) {
/* De-highlight current item */
item_set(scroll + choice);
print_item(list, choice, FALSE);
/* Highlight new item */
choice = i;
item_set(scroll + choice);
print_item(list, choice, TRUE);
wnoutrefresh(dialog);
wrefresh(list);
}
continue; /* wait for another key press */
}
switch (key) {
case 'H':
case 'h':
case '?':
button = 1;
/* fall-through */
case 'S':
case 's':
case ' ':
case '\n':
item_foreach()
item_set_selected(0);
item_set(scroll + choice);
item_set_selected(1);
delwin(list);
delwin(dialog);
return button;
case TAB:
case KEY_LEFT:
case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0)
? 1 : (button > 1 ? 0 : button);
print_buttons(dialog, height, width, button);
wrefresh(dialog);
break;
case 'X':
case 'x':
key = KEY_ESC;
break;
case KEY_ESC:
key = on_key_esc(dialog);
break;
case KEY_RESIZE:
delwin(list);
delwin(dialog);
on_key_resize();
goto do_resize;
}
/* Now, update everything... */
doupdate();
}
delwin(list);
delwin(dialog);
return key; /* ESC pressed */
}

View File

@@ -0,0 +1,257 @@
/*
* dialog.h -- common declarations for all dialog modules
*
* AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifndef KBUILD_NO_NLS
# include <libintl.h>
#else
# define gettext(Msgid) ((const char *) (Msgid))
#endif
#ifdef __sun__
#define CURS_MACROS
#endif
#include CURSES_LOC
/*
* Colors in ncurses 1.9.9e do not work properly since foreground and
* background colors are OR'd rather than separately masked. This version
* of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
* with standard curses. The simplest fix (to make this work with standard
* curses) uses the wbkgdset() function, not used in the original hack.
* Turn it off if we're building with 1.9.9e, since it just confuses things.
*/
#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
#define OLD_NCURSES 1
#undef wbkgdset
#define wbkgdset(w,p) /*nothing */
#else
#define OLD_NCURSES 0
#endif
#define TR(params) _tracef params
#define KEY_ESC 27
#define TAB 9
#define MAX_LEN 2048
#define BUF_SIZE (10*1024)
#define MIN(x,y) (x < y ? x : y)
#define MAX(x,y) (x > y ? x : y)
#ifndef ACS_ULCORNER
#define ACS_ULCORNER '+'
#endif
#ifndef ACS_LLCORNER
#define ACS_LLCORNER '+'
#endif
#ifndef ACS_URCORNER
#define ACS_URCORNER '+'
#endif
#ifndef ACS_LRCORNER
#define ACS_LRCORNER '+'
#endif
#ifndef ACS_HLINE
#define ACS_HLINE '-'
#endif
#ifndef ACS_VLINE
#define ACS_VLINE '|'
#endif
#ifndef ACS_LTEE
#define ACS_LTEE '+'
#endif
#ifndef ACS_RTEE
#define ACS_RTEE '+'
#endif
#ifndef ACS_UARROW
#define ACS_UARROW '^'
#endif
#ifndef ACS_DARROW
#define ACS_DARROW 'v'
#endif
/* error return codes */
#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
/*
* Color definitions
*/
struct dialog_color {
chtype atr; /* Color attribute */
int fg; /* foreground */
int bg; /* background */
int hl; /* highlight this item */
};
struct subtitle_list {
struct subtitle_list *next;
const char *text;
};
struct dialog_info {
const char *backtitle;
struct subtitle_list *subtitles;
struct dialog_color screen;
struct dialog_color shadow;
struct dialog_color dialog;
struct dialog_color title;
struct dialog_color border;
struct dialog_color button_active;
struct dialog_color button_inactive;
struct dialog_color button_key_active;
struct dialog_color button_key_inactive;
struct dialog_color button_label_active;
struct dialog_color button_label_inactive;
struct dialog_color inputbox;
struct dialog_color inputbox_border;
struct dialog_color searchbox;
struct dialog_color searchbox_title;
struct dialog_color searchbox_border;
struct dialog_color position_indicator;
struct dialog_color menubox;
struct dialog_color menubox_border;
struct dialog_color item;
struct dialog_color item_selected;
struct dialog_color tag;
struct dialog_color tag_selected;
struct dialog_color tag_key;
struct dialog_color tag_key_selected;
struct dialog_color check;
struct dialog_color check_selected;
struct dialog_color uarrow;
struct dialog_color darrow;
};
/*
* Global variables
*/
extern struct dialog_info dlg;
extern char dialog_input_result[];
extern int saved_x, saved_y; /* Needed in signal handler in mconf.c */
/*
* Function prototypes
*/
/* item list as used by checklist and menubox */
void item_reset(void);
void item_make(const char *fmt, ...);
void item_add_str(const char *fmt, ...);
void item_set_tag(char tag);
void item_set_data(void *p);
void item_set_selected(int val);
int item_activate_selected(void);
void *item_data(void);
char item_tag(void);
/* item list manipulation for lxdialog use */
#define MAXITEMSTR 200
struct dialog_item {
char str[MAXITEMSTR]; /* prompt displayed */
char tag;
void *data; /* pointer to menu item - used by menubox+checklist */
int selected; /* Set to 1 by dialog_*() function if selected. */
};
/* list of lialog_items */
struct dialog_list {
struct dialog_item node;
struct dialog_list *next;
};
extern struct dialog_list *item_cur;
extern struct dialog_list item_nil;
extern struct dialog_list *item_head;
int item_count(void);
void item_set(int n);
int item_n(void);
const char *item_str(void);
int item_is_selected(void);
int item_is_tag(char tag);
#define item_foreach() \
for (item_cur = item_head ? item_head: item_cur; \
item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
/* generic key handlers */
int on_key_esc(WINDOW *win);
int on_key_resize(void);
/* minimum (re)size values */
#define CHECKLIST_HEIGTH_MIN 6 /* For dialog_checklist() */
#define CHECKLIST_WIDTH_MIN 6
#define INPUTBOX_HEIGTH_MIN 2 /* For dialog_inputbox() */
#define INPUTBOX_WIDTH_MIN 2
#define MENUBOX_HEIGTH_MIN 15 /* For dialog_menu() */
#define MENUBOX_WIDTH_MIN 65
#define TEXTBOX_HEIGTH_MIN 8 /* For dialog_textbox() */
#define TEXTBOX_WIDTH_MIN 8
#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
#define YESNO_WIDTH_MIN 4
#define WINDOW_HEIGTH_MIN 19 /* For init_dialog() */
#define WINDOW_WIDTH_MIN 80
int init_dialog(const char *backtitle);
void set_dialog_backtitle(const char *backtitle);
void set_dialog_subtitles(struct subtitle_list *subtitles);
void end_dialog(int x, int y);
void attr_clear(WINDOW * win, int height, int width, chtype attr);
void dialog_clear(void);
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
void print_button(WINDOW * win, const char *label, int y, int x, int selected);
void print_title(WINDOW *dialog, const char *title, int width);
void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
chtype border);
void draw_shadow(WINDOW * win, int y, int x, int height, int width);
int first_alpha(const char *string, const char *exempt);
int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
*_data);
int dialog_textbox(const char *title, char *tbuf, int initial_height,
int initial_width, int *keys, int *_vscroll, int *_hscroll,
update_text_fn update_text, void *data);
int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height);
int dialog_inputbox(const char *title, const char *prompt, int height,
int width, const char *init);
/*
* This is the base for fictitious keys, which activate
* the buttons.
*
* Mouse-generated keys are the following:
* -- the first 32 are used as numbers, in addition to '0'-'9'
* -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
* -- uppercase chars are used to invoke the button (M_EVENT + 'O')
*/
#define M_EVENT (KEY_MAX+1)

View File

@@ -0,0 +1,301 @@
/*
* inputbox.c -- implements the input box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
char dialog_input_result[MAX_LEN + 1];
/*
* Print the termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 11;
int y = height - 2;
print_button(dialog, gettext(" Ok "), y, x, selected == 0);
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
wmove(dialog, y, x + 1 + 14 * selected);
wrefresh(dialog);
}
/*
* Display a dialog box for inputing a string
*/
int dialog_inputbox(const char *title, const char *prompt, int height, int width,
const char *init)
{
int i, x, y, box_y, box_x, box_width;
int input_x = 0, key = 0, button = -1;
int show_x, len, pos;
char *instr = dialog_input_result;
WINDOW *dialog;
if (!init)
instr[0] = '\0';
else
strcpy(instr, init);
do_resize:
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
/* Draw the input field box */
box_width = width - 6;
getyx(dialog, y, x);
box_y = y + 2;
box_x = (width - box_width) / 2;
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
dlg.dialog.atr, dlg.border.atr);
print_buttons(dialog, height, width, 0);
/* Set up the initial value */
wmove(dialog, box_y, box_x);
wattrset(dialog, dlg.inputbox.atr);
len = strlen(instr);
pos = len;
if (len >= box_width) {
show_x = len - box_width + 1;
input_x = box_width - 1;
for (i = 0; i < box_width - 1; i++)
waddch(dialog, instr[show_x + i]);
} else {
show_x = 0;
input_x = len;
waddstr(dialog, instr);
}
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
while (key != KEY_ESC) {
key = wgetch(dialog);
if (button == -1) { /* Input box selected */
switch (key) {
case TAB:
case KEY_UP:
case KEY_DOWN:
break;
case KEY_BACKSPACE:
case 127:
if (pos) {
wattrset(dialog, dlg.inputbox.atr);
if (input_x == 0) {
show_x--;
} else
input_x--;
if (pos < len) {
for (i = pos - 1; i < len; i++) {
instr[i] = instr[i+1];
}
}
pos--;
len--;
instr[len] = '\0';
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
wrefresh(dialog);
}
continue;
case KEY_LEFT:
if (pos > 0) {
if (input_x > 0) {
wmove(dialog, box_y, --input_x + box_x);
} else if (input_x == 0) {
show_x--;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, box_x);
}
pos--;
}
continue;
case KEY_RIGHT:
if (pos < len) {
if (input_x < box_width - 1) {
wmove(dialog, box_y, ++input_x + box_x);
} else if (input_x == box_width - 1) {
show_x++;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
}
pos++;
}
continue;
default:
if (key < 0x100 && isprint(key)) {
if (len < MAX_LEN) {
wattrset(dialog, dlg.inputbox.atr);
if (pos < len) {
for (i = len; i > pos; i--)
instr[i] = instr[i-1];
instr[pos] = key;
} else {
instr[len] = key;
}
pos++;
len++;
instr[len] = '\0';
if (input_x == box_width - 1) {
show_x++;
} else {
input_x++;
}
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
wrefresh(dialog);
} else
flash(); /* Alarm user about overflow */
continue;
}
}
}
switch (key) {
case 'O':
case 'o':
delwin(dialog);
return 0;
case 'H':
case 'h':
delwin(dialog);
return 1;
case KEY_UP:
case KEY_LEFT:
switch (button) {
case -1:
button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 0:
button = -1; /* Indicates input box is selected */
print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
break;
case 1:
button = 0; /* Indicates "OK" button is selected */
print_buttons(dialog, height, width, 0);
break;
}
break;
case TAB:
case KEY_DOWN:
case KEY_RIGHT:
switch (button) {
case -1:
button = 0; /* Indicates "OK" button is selected */
print_buttons(dialog, height, width, 0);
break;
case 0:
button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 1:
button = -1; /* Indicates input box is selected */
print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
break;
}
break;
case ' ':
case '\n':
delwin(dialog);
return (button == -1 ? 0 : button);
case 'X':
case 'x':
key = KEY_ESC;
break;
case KEY_ESC:
key = on_key_esc(dialog);
break;
case KEY_RESIZE:
delwin(dialog);
on_key_resize();
goto do_resize;
}
}
delwin(dialog);
return KEY_ESC; /* ESC pressed */
}

View File

@@ -0,0 +1,437 @@
/*
* menubox.c -- implements the menu box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Changes by Clifford Wolf (god@clifford.at)
*
* [ 1998-06-13 ]
*
* *) A bugfix for the Page-Down problem
*
* *) Formerly when I used Page Down and Page Up, the cursor would be set
* to the first position in the menu box. Now lxdialog is a bit
* smarter and works more like other menu systems (just have a look at
* it).
*
* *) Formerly if I selected something my scrolling would be broken because
* lxdialog is re-invoked by the Menuconfig shell script, can't
* remember the last scrolling position, and just sets it so that the
* cursor is at the bottom of the box. Now it writes the temporary file
* lxdialog.scrltmp which contains this information. The file is
* deleted by lxdialog if the user leaves a submenu or enters a new
* one, but it would be nice if Menuconfig could make another "rm -f"
* just to be sure. Just try it out - you will recognise a difference!
*
* [ 1998-06-14 ]
*
* *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
* and menus change their size on the fly.
*
* *) If for some reason the last scrolling position is not saved by
* lxdialog, it sets the scrolling so that the selected item is in the
* middle of the menu box, not at the bottom.
*
* 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
* Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
* This fixes a bug in Menuconfig where using ' ' to descend into menus
* would leave mis-synchronized lxdialog.scrltmp files lying around,
* fscanf would read in 'scroll', and eventually that value would get used.
*/
#include "dialog.h"
static int menu_width, item_x;
/*
* Print menu item
*/
static void do_print_item(WINDOW * win, const char *item, int line_y,
int selected, int hotkey)
{
int j;
char *menu_item = malloc(menu_width + 1);
strncpy(menu_item, item, menu_width - item_x);
menu_item[menu_width - item_x] = '\0';
j = first_alpha(menu_item, "YyNnMmHh");
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
wmove(win, line_y, 0);
#if OLD_NCURSES
{
int i;
for (i = 0; i < menu_width; i++)
waddch(win, ' ');
}
#else
wclrtoeol(win);
#endif
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
mvwaddstr(win, line_y, item_x, menu_item);
if (hotkey) {
wattrset(win, selected ? dlg.tag_key_selected.atr
: dlg.tag_key.atr);
mvwaddch(win, line_y, item_x + j, menu_item[j]);
}
if (selected) {
wmove(win, line_y, item_x + 1);
}
free(menu_item);
wrefresh(win);
}
#define print_item(index, choice, selected) \
do { \
item_set(index); \
do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
} while (0)
/*
* Print the scroll indicators.
*/
static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
int height)
{
int cur_y, cur_x;
getyx(win, cur_y, cur_x);
wmove(win, y, x);
if (scroll > 0) {
wattrset(win, dlg.uarrow.atr);
waddch(win, ACS_UARROW);
waddstr(win, "(-)");
} else {
wattrset(win, dlg.menubox.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
y = y + height + 1;
wmove(win, y, x);
wrefresh(win);
if ((height < item_no) && (scroll + height < item_no)) {
wattrset(win, dlg.darrow.atr);
waddch(win, ACS_DARROW);
waddstr(win, "(+)");
} else {
wattrset(win, dlg.menubox_border.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
}
wmove(win, cur_y, cur_x);
wrefresh(win);
}
/*
* Display the termination buttons.
*/
static void print_buttons(WINDOW * win, int height, int width, int selected)
{
int x = width / 2 - 28;
int y = height - 2;
print_button(win, gettext("Select"), y, x, selected == 0);
print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
print_button(win, gettext(" Help "), y, x + 24, selected == 2);
print_button(win, gettext(" Save "), y, x + 36, selected == 3);
print_button(win, gettext(" Load "), y, x + 48, selected == 4);
wmove(win, y, x + 1 + 12 * selected);
wrefresh(win);
}
/* scroll up n lines (n may be negative) */
static void do_scroll(WINDOW *win, int *scroll, int n)
{
/* Scroll menu up */
scrollok(win, TRUE);
wscrl(win, n);
scrollok(win, FALSE);
*scroll = *scroll + n;
wrefresh(win);
}
/*
* Display a menu for choosing among a number of options
*/
int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll)
{
int i, j, x, y, box_x, box_y;
int height, width, menu_height;
int key = 0, button = 0, scroll = 0, choice = 0;
int first_item = 0, max_choice;
WINDOW *dialog, *menu;
do_resize:
height = getmaxy(stdscr);
width = getmaxx(stdscr);
if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
return -ERRDISPLAYTOOSMALL;
height -= 4;
width -= 5;
menu_height = height - 10;
max_choice = MIN(menu_height, item_count());
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
menu_width = width - 6;
box_y = height - menu_height - 5;
box_x = (width - menu_width) / 2 - 1;
/* create new window for the menu */
menu = subwin(dialog, menu_height, menu_width,
y + box_y + 1, x + box_x + 1);
keypad(menu, TRUE);
/* draw a box around the menu items */
draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
dlg.menubox_border.atr, dlg.menubox.atr);
if (menu_width >= 80)
item_x = (menu_width - 70) / 2;
else
item_x = 4;
/* Set choice to default item */
item_foreach()
if (selected && (selected == item_data()))
choice = item_n();
/* get the saved scroll info */
scroll = *s_scroll;
if ((scroll <= choice) && (scroll + max_choice > choice) &&
(scroll >= 0) && (scroll + max_choice <= item_count())) {
first_item = scroll;
choice = choice - scroll;
} else {
scroll = 0;
}
if ((choice >= max_choice)) {
if (choice >= item_count() - max_choice / 2)
scroll = first_item = item_count() - max_choice;
else
scroll = first_item = choice - max_choice / 2;
choice = choice - scroll;
}
/* Print the menu */
for (i = 0; i < max_choice; i++) {
print_item(first_item + i, i, i == choice);
}
wnoutrefresh(menu);
print_arrows(dialog, item_count(), scroll,
box_y, box_x + item_x + 1, menu_height);
print_buttons(dialog, height, width, 0);
wmove(menu, choice, item_x + 1);
wrefresh(menu);
while (key != KEY_ESC) {
key = wgetch(menu);
if (key < 256 && isalpha(key))
key = tolower(key);
if (strchr("ynmh", key))
i = max_choice;
else {
for (i = choice + 1; i < max_choice; i++) {
item_set(scroll + i);
j = first_alpha(item_str(), "YyNnMmHh");
if (key == tolower(item_str()[j]))
break;
}
if (i == max_choice)
for (i = 0; i < max_choice; i++) {
item_set(scroll + i);
j = first_alpha(item_str(), "YyNnMmHh");
if (key == tolower(item_str()[j]))
break;
}
}
if (item_count() != 0 &&
(i < max_choice ||
key == KEY_UP || key == KEY_DOWN ||
key == '-' || key == '+' ||
key == KEY_PPAGE || key == KEY_NPAGE)) {
/* Remove highligt of current item */
print_item(scroll + choice, choice, FALSE);
if (key == KEY_UP || key == '-') {
if (choice < 2 && scroll) {
/* Scroll menu down */
do_scroll(menu, &scroll, -1);
print_item(scroll, 0, FALSE);
} else
choice = MAX(choice - 1, 0);
} else if (key == KEY_DOWN || key == '+') {
print_item(scroll+choice, choice, FALSE);
if ((choice > max_choice - 3) &&
(scroll + max_choice < item_count())) {
/* Scroll menu up */
do_scroll(menu, &scroll, 1);
print_item(scroll+max_choice - 1,
max_choice - 1, FALSE);
} else
choice = MIN(choice + 1, max_choice - 1);
} else if (key == KEY_PPAGE) {
scrollok(menu, TRUE);
for (i = 0; (i < max_choice); i++) {
if (scroll > 0) {
do_scroll(menu, &scroll, -1);
print_item(scroll, 0, FALSE);
} else {
if (choice > 0)
choice--;
}
}
} else if (key == KEY_NPAGE) {
for (i = 0; (i < max_choice); i++) {
if (scroll + max_choice < item_count()) {
do_scroll(menu, &scroll, 1);
print_item(scroll+max_choice-1,
max_choice - 1, FALSE);
} else {
if (choice + 1 < max_choice)
choice++;
}
}
} else
choice = i;
print_item(scroll + choice, choice, TRUE);
print_arrows(dialog, item_count(), scroll,
box_y, box_x + item_x + 1, menu_height);
wnoutrefresh(dialog);
wrefresh(menu);
continue; /* wait for another key press */
}
switch (key) {
case KEY_LEFT:
case TAB:
case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0)
? 4 : (button > 4 ? 0 : button);
print_buttons(dialog, height, width, button);
wrefresh(menu);
break;
case ' ':
case 's':
case 'y':
case 'n':
case 'm':
case '/':
case 'h':
case '?':
case 'z':
case '\n':
/* save scroll info */
*s_scroll = scroll;
delwin(menu);
delwin(dialog);
item_set(scroll + choice);
item_set_selected(1);
switch (key) {
case 'h':
case '?':
return 2;
case 's':
case 'y':
return 5;
case 'n':
return 6;
case 'm':
return 7;
case ' ':
return 8;
case '/':
return 9;
case 'z':
return 10;
case '\n':
return button;
}
return 0;
case 'e':
case 'x':
key = KEY_ESC;
break;
case KEY_ESC:
key = on_key_esc(menu);
break;
case KEY_RESIZE:
on_key_resize();
delwin(menu);
delwin(dialog);
goto do_resize;
}
}
delwin(menu);
delwin(dialog);
return key; /* ESC pressed */
}

View File

@@ -0,0 +1,408 @@
/*
* textbox.c -- implements the text box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
static void back_lines(int n);
static void print_page(WINDOW *win, int height, int width, update_text_fn
update_text, void *data);
static void print_line(WINDOW *win, int row, int width);
static char *get_line(void);
static void print_position(WINDOW * win);
static int hscroll;
static int begin_reached, end_reached, page_length;
static char *buf;
static char *page;
/*
* refresh window content
*/
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
int cur_y, int cur_x, update_text_fn update_text,
void *data)
{
print_page(box, boxh, boxw, update_text, data);
print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
}
/*
* Display text from a file in a dialog box.
*
* keys is a null-terminated array
* update_text() may not add or remove any '\n' or '\0' in tbuf
*/
int dialog_textbox(const char *title, char *tbuf, int initial_height,
int initial_width, int *keys, int *_vscroll, int *_hscroll,
update_text_fn update_text, void *data)
{
int i, x, y, cur_x, cur_y, key = 0;
int height, width, boxh, boxw;
WINDOW *dialog, *box;
bool done = false;
begin_reached = 1;
end_reached = 0;
page_length = 0;
hscroll = 0;
buf = tbuf;
page = buf; /* page is pointer to start of page to be displayed */
if (_vscroll && *_vscroll) {
begin_reached = 0;
for (i = 0; i < *_vscroll; i++)
get_line();
}
if (_hscroll)
hscroll = *_hscroll;
do_resize:
getmaxyx(stdscr, height, width);
if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
return -ERRDISPLAYTOOSMALL;
if (initial_height != 0)
height = initial_height;
else
if (height > 4)
height -= 4;
else
height = 0;
if (initial_width != 0)
width = initial_width;
else
if (width > 5)
width -= 5;
else
width = 0;
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
/* Create window for box region, used for scrolling text */
boxh = height - 4;
boxw = width - 2;
box = subwin(dialog, boxh, boxw, y + 1, x + 1);
wattrset(box, dlg.dialog.atr);
wbkgdset(box, dlg.dialog.atr & A_COLOR);
keypad(box, TRUE);
/* register the new window, along with its borders */
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
wnoutrefresh(dialog);
getyx(dialog, cur_y, cur_x); /* Save cursor position */
/* Print first page of text */
attr_clear(box, boxh, boxw, dlg.dialog.atr);
refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
data);
while (!done) {
key = wgetch(dialog);
switch (key) {
case 'E': /* Exit */
case 'e':
case 'X':
case 'x':
case 'q':
case '\n':
done = true;
break;
case 'g': /* First page */
case KEY_HOME:
if (!begin_reached) {
begin_reached = 1;
page = buf;
refresh_text_box(dialog, box, boxh, boxw,
cur_y, cur_x, update_text,
data);
}
break;
case 'G': /* Last page */
case KEY_END:
end_reached = 1;
/* point to last char in buf */
page = buf + strlen(buf);
back_lines(boxh);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case 'K': /* Previous line */
case 'k':
case KEY_UP:
if (begin_reached)
break;
back_lines(page_length + 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case 'B': /* Previous page */
case 'b':
case 'u':
case KEY_PPAGE:
if (begin_reached)
break;
back_lines(page_length + boxh);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case 'J': /* Next line */
case 'j':
case KEY_DOWN:
if (end_reached)
break;
back_lines(page_length - 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case KEY_NPAGE: /* Next page */
case ' ':
case 'd':
if (end_reached)
break;
begin_reached = 0;
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case '0': /* Beginning of line */
case 'H': /* Scroll left */
case 'h':
case KEY_LEFT:
if (hscroll <= 0)
break;
if (key == '0')
hscroll = 0;
else
hscroll--;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case 'L': /* Scroll right */
case 'l':
case KEY_RIGHT:
if (hscroll >= MAX_LEN)
break;
hscroll++;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
cur_x, update_text, data);
break;
case KEY_ESC:
if (on_key_esc(dialog) == KEY_ESC)
done = true;
break;
case KEY_RESIZE:
back_lines(height);
delwin(box);
delwin(dialog);
on_key_resize();
goto do_resize;
default:
for (i = 0; keys[i]; i++) {
if (key == keys[i]) {
done = true;
break;
}
}
}
}
delwin(box);
delwin(dialog);
if (_vscroll) {
const char *s;
s = buf;
*_vscroll = 0;
back_lines(page_length);
while (s < page && (s = strchr(s, '\n'))) {
(*_vscroll)++;
s++;
}
}
if (_hscroll)
*_hscroll = hscroll;
return key;
}
/*
* Go back 'n' lines in text. Called by dialog_textbox().
* 'page' will be updated to point to the desired line in 'buf'.
*/
static void back_lines(int n)
{
int i;
begin_reached = 0;
/* Go back 'n' lines */
for (i = 0; i < n; i++) {
if (*page == '\0') {
if (end_reached) {
end_reached = 0;
continue;
}
}
if (page == buf) {
begin_reached = 1;
return;
}
page--;
do {
if (page == buf) {
begin_reached = 1;
return;
}
page--;
} while (*page != '\n');
page++;
}
}
/*
* Print a new page of text.
*/
static void print_page(WINDOW *win, int height, int width, update_text_fn
update_text, void *data)
{
int i, passed_end = 0;
if (update_text) {
char *end;
for (i = 0; i < height; i++)
get_line();
end = page;
back_lines(height);
update_text(buf, page - buf, end - buf, data);
}
page_length = 0;
for (i = 0; i < height; i++) {
print_line(win, i, width);
if (!passed_end)
page_length++;
if (end_reached && !passed_end)
passed_end = 1;
}
wnoutrefresh(win);
}
/*
* Print a new line of text.
*/
static void print_line(WINDOW * win, int row, int width)
{
char *line;
line = get_line();
line += MIN(strlen(line), hscroll); /* Scroll horizontally */
wmove(win, row, 0); /* move cursor to correct line */
waddch(win, ' ');
waddnstr(win, line, MIN(strlen(line), width - 2));
/* Clear 'residue' of previous line */
#if OLD_NCURSES
{
int x = getcurx(win);
int i;
for (i = 0; i < width - x; i++)
waddch(win, ' ');
}
#else
wclrtoeol(win);
#endif
}
/*
* Return current line of text. Called by dialog_textbox() and print_line().
* 'page' should point to start of current line before calling, and will be
* updated to point to start of next line.
*/
static char *get_line(void)
{
int i = 0;
static char line[MAX_LEN + 1];
end_reached = 0;
while (*page != '\n') {
if (*page == '\0') {
end_reached = 1;
break;
} else if (i < MAX_LEN)
line[i++] = *(page++);
else {
/* Truncate lines longer than MAX_LEN characters */
if (i == MAX_LEN)
line[i++] = '\0';
page++;
}
}
if (i <= MAX_LEN)
line[i] = '\0';
if (!end_reached)
page++; /* move past '\n' */
return line;
}
/*
* Print current position
*/
static void print_position(WINDOW * win)
{
int percent;
wattrset(win, dlg.position_indicator.atr);
wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
percent = (page - buf) * 100 / strlen(buf);
wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
wprintw(win, "(%3d%%)", percent);
}

View File

@@ -0,0 +1,713 @@
/*
* util.c
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdarg.h>
#include "dialog.h"
/* Needed in signal handler in mconf.c */
int saved_x, saved_y;
struct dialog_info dlg;
static void set_mono_theme(void)
{
dlg.screen.atr = A_NORMAL;
dlg.shadow.atr = A_NORMAL;
dlg.dialog.atr = A_NORMAL;
dlg.title.atr = A_BOLD;
dlg.border.atr = A_NORMAL;
dlg.button_active.atr = A_REVERSE;
dlg.button_inactive.atr = A_DIM;
dlg.button_key_active.atr = A_REVERSE;
dlg.button_key_inactive.atr = A_BOLD;
dlg.button_label_active.atr = A_REVERSE;
dlg.button_label_inactive.atr = A_NORMAL;
dlg.inputbox.atr = A_NORMAL;
dlg.inputbox_border.atr = A_NORMAL;
dlg.searchbox.atr = A_NORMAL;
dlg.searchbox_title.atr = A_BOLD;
dlg.searchbox_border.atr = A_NORMAL;
dlg.position_indicator.atr = A_BOLD;
dlg.menubox.atr = A_NORMAL;
dlg.menubox_border.atr = A_NORMAL;
dlg.item.atr = A_NORMAL;
dlg.item_selected.atr = A_REVERSE;
dlg.tag.atr = A_BOLD;
dlg.tag_selected.atr = A_REVERSE;
dlg.tag_key.atr = A_BOLD;
dlg.tag_key_selected.atr = A_REVERSE;
dlg.check.atr = A_BOLD;
dlg.check_selected.atr = A_REVERSE;
dlg.uarrow.atr = A_BOLD;
dlg.darrow.atr = A_BOLD;
}
#define DLG_COLOR(dialog, f, b, h) \
do { \
dlg.dialog.fg = (f); \
dlg.dialog.bg = (b); \
dlg.dialog.hl = (h); \
} while (0)
static void set_classic_theme(void)
{
DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
}
static void set_blackbg_theme(void)
{
DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
}
static void set_bluetitle_theme(void)
{
set_classic_theme();
DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
}
/*
* Select color theme
*/
static int set_theme(const char *theme)
{
int use_color = 1;
if (!theme)
set_bluetitle_theme();
else if (strcmp(theme, "classic") == 0)
set_classic_theme();
else if (strcmp(theme, "bluetitle") == 0)
set_bluetitle_theme();
else if (strcmp(theme, "blackbg") == 0)
set_blackbg_theme();
else if (strcmp(theme, "mono") == 0)
use_color = 0;
return use_color;
}
static void init_one_color(struct dialog_color *color)
{
static int pair = 0;
pair++;
init_pair(pair, color->fg, color->bg);
if (color->hl)
color->atr = A_BOLD | COLOR_PAIR(pair);
else
color->atr = COLOR_PAIR(pair);
}
static void init_dialog_colors(void)
{
init_one_color(&dlg.screen);
init_one_color(&dlg.shadow);
init_one_color(&dlg.dialog);
init_one_color(&dlg.title);
init_one_color(&dlg.border);
init_one_color(&dlg.button_active);
init_one_color(&dlg.button_inactive);
init_one_color(&dlg.button_key_active);
init_one_color(&dlg.button_key_inactive);
init_one_color(&dlg.button_label_active);
init_one_color(&dlg.button_label_inactive);
init_one_color(&dlg.inputbox);
init_one_color(&dlg.inputbox_border);
init_one_color(&dlg.searchbox);
init_one_color(&dlg.searchbox_title);
init_one_color(&dlg.searchbox_border);
init_one_color(&dlg.position_indicator);
init_one_color(&dlg.menubox);
init_one_color(&dlg.menubox_border);
init_one_color(&dlg.item);
init_one_color(&dlg.item_selected);
init_one_color(&dlg.tag);
init_one_color(&dlg.tag_selected);
init_one_color(&dlg.tag_key);
init_one_color(&dlg.tag_key_selected);
init_one_color(&dlg.check);
init_one_color(&dlg.check_selected);
init_one_color(&dlg.uarrow);
init_one_color(&dlg.darrow);
}
/*
* Setup for color display
*/
static void color_setup(const char *theme)
{
int use_color;
use_color = set_theme(theme);
if (use_color && has_colors()) {
start_color();
init_dialog_colors();
} else
set_mono_theme();
}
/*
* Set window to attribute 'attr'
*/
void attr_clear(WINDOW * win, int height, int width, chtype attr)
{
int i, j;
wattrset(win, attr);
for (i = 0; i < height; i++) {
wmove(win, i, 0);
for (j = 0; j < width; j++)
waddch(win, ' ');
}
touchwin(win);
}
void dialog_clear(void)
{
int lines, columns;
lines = getmaxy(stdscr);
columns = getmaxx(stdscr);
attr_clear(stdscr, lines, columns, dlg.screen.atr);
/* Display background title if it exists ... - SLH */
if (dlg.backtitle != NULL) {
int i, len = 0, skip = 0;
struct subtitle_list *pos;
wattrset(stdscr, dlg.screen.atr);
mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
/* 3 is for the arrow and spaces */
len += strlen(pos->text) + 3;
}
wmove(stdscr, 1, 1);
if (len > columns - 2) {
const char *ellipsis = "[...] ";
waddstr(stdscr, ellipsis);
skip = len - (columns - 2 - strlen(ellipsis));
}
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
if (skip == 0)
waddch(stdscr, ACS_RARROW);
else
skip--;
if (skip == 0)
waddch(stdscr, ' ');
else
skip--;
if (skip < strlen(pos->text)) {
waddstr(stdscr, pos->text + skip);
skip = 0;
} else
skip -= strlen(pos->text);
if (skip == 0)
waddch(stdscr, ' ');
else
skip--;
}
for (i = len + 1; i < columns - 1; i++)
waddch(stdscr, ACS_HLINE);
}
wnoutrefresh(stdscr);
}
/*
* Do some initialization for dialog
*/
int init_dialog(const char *backtitle)
{
int height, width;
initscr(); /* Init curses */
/* Get current cursor position for signal handler in mconf.c */
getyx(stdscr, saved_y, saved_x);
getmaxyx(stdscr, height, width);
if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
endwin();
return -ERRDISPLAYTOOSMALL;
}
dlg.backtitle = backtitle;
color_setup(getenv("MENUCONFIG_COLOR"));
keypad(stdscr, TRUE);
cbreak();
noecho();
dialog_clear();
return 0;
}
void set_dialog_backtitle(const char *backtitle)
{
dlg.backtitle = backtitle;
}
void set_dialog_subtitles(struct subtitle_list *subtitles)
{
dlg.subtitles = subtitles;
}
/*
* End using dialog functions.
*/
void end_dialog(int x, int y)
{
/* move cursor back to original position */
move(y, x);
refresh();
endwin();
}
/* Print the title of the dialog. Center the title and truncate
* tile if wider than dialog (- 2 chars).
**/
void print_title(WINDOW *dialog, const char *title, int width)
{
if (title) {
int tlen = MIN(width - 2, strlen(title));
wattrset(dialog, dlg.title.atr);
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
waddch(dialog, ' ');
}
}
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are propperly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{
int newl, cur_x, cur_y;
int prompt_len, room, wlen;
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
strcpy(tempstr, prompt);
prompt_len = strlen(tempstr);
if (prompt_len <= width - x * 2) { /* If prompt is short */
wmove(win, y, (width - prompt_len) / 2);
waddstr(win, tempstr);
} else {
cur_x = x;
cur_y = y;
newl = 1;
word = tempstr;
while (word && *word) {
sp = strpbrk(word, "\n ");
if (sp && *sp == '\n')
newline_separator = sp;
if (sp)
*sp++ = 0;
/* Wrap to next line if either the word does not fit,
or it is the first word of a new sentence, and it is
short, and the next word does not fit. */
room = width - cur_x;
wlen = strlen(word);
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++;
cur_x = x;
}
wmove(win, cur_y, cur_x);
waddstr(win, word);
getyx(win, cur_y, cur_x);
/* Move to the next line if the word separator was a newline */
if (newline_separator) {
cur_y++;
cur_x = x;
newline_separator = 0;
} else
cur_x++;
if (sp && *sp == ' ') {
cur_x++; /* double space */
while (*++sp == ' ') ;
newl = 1;
} else
newl = 0;
word = sp;
}
}
}
/*
* Print a button
*/
void print_button(WINDOW * win, const char *label, int y, int x, int selected)
{
int i, temp;
wmove(win, y, x);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, "<");
temp = strspn(label, " ");
label += temp;
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
for (i = 0; i < temp; i++)
waddch(win, ' ');
wattrset(win, selected ? dlg.button_key_active.atr
: dlg.button_key_inactive.atr);
waddch(win, label[0]);
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
waddstr(win, (char *)label + 1);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, ">");
wmove(win, y, x + temp + 1);
}
/*
* Draw a rectangular box with line drawing characters
*/
void
draw_box(WINDOW * win, int y, int x, int height, int width,
chtype box, chtype border)
{
int i, j;
wattrset(win, 0);
for (i = 0; i < height; i++) {
wmove(win, y + i, x);
for (j = 0; j < width; j++)
if (!i && !j)
waddch(win, border | ACS_ULCORNER);
else if (i == height - 1 && !j)
waddch(win, border | ACS_LLCORNER);
else if (!i && j == width - 1)
waddch(win, box | ACS_URCORNER);
else if (i == height - 1 && j == width - 1)
waddch(win, box | ACS_LRCORNER);
else if (!i)
waddch(win, border | ACS_HLINE);
else if (i == height - 1)
waddch(win, box | ACS_HLINE);
else if (!j)
waddch(win, border | ACS_VLINE);
else if (j == width - 1)
waddch(win, box | ACS_VLINE);
else
waddch(win, box | ' ');
}
}
/*
* Draw shadows along the right and bottom edge to give a more 3D look
* to the boxes
*/
void draw_shadow(WINDOW * win, int y, int x, int height, int width)
{
int i;
if (has_colors()) { /* Whether terminal supports color? */
wattrset(win, dlg.shadow.atr);
wmove(win, y + height, x + 2);
for (i = 0; i < width; i++)
waddch(win, winch(win) & A_CHARTEXT);
for (i = y + 1; i < y + height + 1; i++) {
wmove(win, i, x + width);
waddch(win, winch(win) & A_CHARTEXT);
waddch(win, winch(win) & A_CHARTEXT);
}
wnoutrefresh(win);
}
}
/*
* Return the position of the first alphabetic character in a string.
*/
int first_alpha(const char *string, const char *exempt)
{
int i, in_paren = 0, c;
for (i = 0; i < strlen(string); i++) {
c = tolower(string[i]);
if (strchr("<[(", c))
++in_paren;
if (strchr(">])", c) && in_paren > 0)
--in_paren;
if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
return i;
}
return 0;
}
/*
* ncurses uses ESC to detect escaped char sequences. This resutl in
* a small timeout before ESC is actually delivered to the application.
* lxdialog suggest <ESC> <ESC> which is correctly translated to two
* times esc. But then we need to ignore the second esc to avoid stepping
* out one menu too much. Filter away all escaped key sequences since
* keypad(FALSE) turn off ncurses support for escape sequences - and thats
* needed to make notimeout() do as expected.
*/
int on_key_esc(WINDOW *win)
{
int key;
int key2;
int key3;
nodelay(win, TRUE);
keypad(win, FALSE);
key = wgetch(win);
key2 = wgetch(win);
do {
key3 = wgetch(win);
} while (key3 != ERR);
nodelay(win, FALSE);
keypad(win, TRUE);
if (key == KEY_ESC && key2 == ERR)
return KEY_ESC;
else if (key != ERR && key != KEY_ESC && key2 == ERR)
ungetch(key);
return -1;
}
/* redraw screen in new size */
int on_key_resize(void)
{
dialog_clear();
return KEY_RESIZE;
}
struct dialog_list *item_cur;
struct dialog_list item_nil;
struct dialog_list *item_head;
void item_reset(void)
{
struct dialog_list *p, *next;
for (p = item_head; p; p = next) {
next = p->next;
free(p);
}
item_head = NULL;
item_cur = &item_nil;
}
void item_make(const char *fmt, ...)
{
va_list ap;
struct dialog_list *p = malloc(sizeof(*p));
if (item_head)
item_cur->next = p;
else
item_head = p;
item_cur = p;
memset(p, 0, sizeof(*p));
va_start(ap, fmt);
vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
va_end(ap);
}
void item_add_str(const char *fmt, ...)
{
va_list ap;
size_t avail;
avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
va_start(ap, fmt);
vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
avail, fmt, ap);
item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
va_end(ap);
}
void item_set_tag(char tag)
{
item_cur->node.tag = tag;
}
void item_set_data(void *ptr)
{
item_cur->node.data = ptr;
}
void item_set_selected(int val)
{
item_cur->node.selected = val;
}
int item_activate_selected(void)
{
item_foreach()
if (item_is_selected())
return 1;
return 0;
}
void *item_data(void)
{
return item_cur->node.data;
}
char item_tag(void)
{
return item_cur->node.tag;
}
int item_count(void)
{
int n = 0;
struct dialog_list *p;
for (p = item_head; p; p = p->next)
n++;
return n;
}
void item_set(int n)
{
int i = 0;
item_foreach()
if (i++ == n)
return;
}
int item_n(void)
{
int n = 0;
struct dialog_list *p;
for (p = item_head; p; p = p->next) {
if (p == item_cur)
return n;
n++;
}
return 0;
}
const char *item_str(void)
{
return item_cur->node.str;
}
int item_is_selected(void)
{
return (item_cur->node.selected != 0);
}
int item_is_tag(char tag)
{
return (item_cur->node.tag == tag);
}

View File

@@ -0,0 +1,114 @@
/*
* yesno.c -- implements the yes/no box
*
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
/*
* Display termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 10;
int y = height - 2;
print_button(dialog, gettext(" Yes "), y, x, selected == 0);
print_button(dialog, gettext(" No "), y, x + 13, selected == 1);
wmove(dialog, y, x + 1 + 13 * selected);
wrefresh(dialog);
}
/*
* Display a dialog box with two buttons - Yes and No
*/
int dialog_yesno(const char *title, const char *prompt, int height, int width)
{
int i, x, y, key = 0, button = 0;
WINDOW *dialog;
do_resize:
if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
print_buttons(dialog, height, width, 0);
while (key != KEY_ESC) {
key = wgetch(dialog);
switch (key) {
case 'Y':
case 'y':
delwin(dialog);
return 0;
case 'N':
case 'n':
delwin(dialog);
return 1;
case TAB:
case KEY_LEFT:
case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
print_buttons(dialog, height, width, button);
wrefresh(dialog);
break;
case ' ':
case '\n':
delwin(dialog);
return button;
case KEY_ESC:
key = on_key_esc(dialog);
break;
case KEY_RESIZE:
delwin(dialog);
on_key_resize();
goto do_resize;
}
}
delwin(dialog);
return key; /* ESC pressed */
}

1053
scripts/config/mconf.c Normal file

File diff suppressed because it is too large Load Diff

697
scripts/config/menu.c Normal file
View File

@@ -0,0 +1,697 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "lkc.h"
static const char nohelp_text[] = "There is no help available for this option.";
struct menu rootmenu;
static struct menu **last_entry_ptr;
struct file *file_list;
struct file *current_file;
void menu_warn(struct menu *menu, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
}
static void prop_warn(struct property *prop, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
}
void _menu_init(void)
{
current_entry = current_menu = &rootmenu;
last_entry_ptr = &rootmenu.list;
}
void menu_add_entry(struct symbol *sym)
{
struct menu *menu;
menu = xmalloc(sizeof(*menu));
memset(menu, 0, sizeof(*menu));
menu->sym = sym;
menu->parent = current_menu;
menu->file = current_file;
menu->lineno = zconf_lineno();
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
if (sym)
menu_add_symbol(P_SYMBOL, sym, NULL);
}
void menu_end_entry(void)
{
}
struct menu *menu_add_menu(void)
{
menu_end_entry();
last_entry_ptr = &current_entry->list;
return current_menu = current_entry;
}
void menu_end_menu(void)
{
last_entry_ptr = &current_menu->next;
current_menu = current_menu->parent;
}
static struct expr *menu_check_dep(struct expr *e)
{
if (!e)
return e;
switch (e->type) {
case E_NOT:
e->left.expr = menu_check_dep(e->left.expr);
break;
case E_OR:
case E_AND:
e->left.expr = menu_check_dep(e->left.expr);
e->right.expr = menu_check_dep(e->right.expr);
break;
case E_SYMBOL:
/* change 'm' into 'm' && MODULES */
if (e->left.sym == &symbol_mod)
return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
break;
default:
break;
}
return e;
}
void menu_add_dep(struct expr *dep)
{
current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
}
void menu_set_type(int type)
{
struct symbol *sym = current_entry->sym;
if (sym->type == type)
return;
if (sym->type == S_UNKNOWN) {
sym->type = type;
return;
}
menu_warn(current_entry,
"ignoring type redefinition of '%s' from '%s' to '%s'",
sym->name ? sym->name : "<choice>",
sym_type_name(sym->type), sym_type_name(type));
}
struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
struct property *prop = prop_alloc(type, current_entry->sym);
prop->menu = current_entry;
prop->expr = expr;
prop->visible.expr = menu_check_dep(dep);
if (prompt) {
if (isspace(*prompt)) {
prop_warn(prop, "leading whitespace ignored");
while (isspace(*prompt))
prompt++;
}
if (current_entry->prompt && current_entry != &rootmenu)
prop_warn(prop, "prompt redefined");
/* Apply all upper menus' visibilities to actual prompts. */
if(type == P_PROMPT) {
struct menu *menu = current_entry;
while ((menu = menu->parent) != NULL) {
struct expr *dup_expr;
if (!menu->visibility)
continue;
/*
* Do not add a reference to the
* menu's visibility expression but
* use a copy of it. Otherwise the
* expression reduction functions
* will modify expressions that have
* multiple references which can
* cause unwanted side effects.
*/
dup_expr = expr_copy(menu->visibility);
prop->visible.expr
= expr_alloc_and(prop->visible.expr,
dup_expr);
}
}
current_entry->prompt = prop;
}
prop->text = prompt;
return prop;
}
struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
{
return menu_add_prop(type, prompt, NULL, dep);
}
void menu_add_visibility(struct expr *expr)
{
current_entry->visibility = expr_alloc_and(current_entry->visibility,
expr);
}
void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{
menu_add_prop(type, NULL, expr, dep);
}
void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
{
menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
}
void menu_add_option(int token, char *arg)
{
switch (token) {
case T_OPT_MODULES:
if (modules_sym)
zconf_error("symbol '%s' redefines option 'modules'"
" already defined by symbol '%s'",
current_entry->sym->name,
modules_sym->name
);
modules_sym = current_entry->sym;
break;
case T_OPT_DEFCONFIG_LIST:
if (!sym_defconfig_list)
sym_defconfig_list = current_entry->sym;
else if (sym_defconfig_list != current_entry->sym)
zconf_error("trying to redefine defconfig symbol");
break;
case T_OPT_ENV:
prop_add_env(arg);
break;
case T_OPT_ALLNOCONFIG_Y:
current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
break;
}
}
static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
{
return sym2->type == S_INT || sym2->type == S_HEX ||
(sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
}
static void sym_check_prop(struct symbol *sym)
{
struct property *prop;
struct symbol *sym2;
for (prop = sym->prop; prop; prop = prop->next) {
switch (prop->type) {
case P_DEFAULT:
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
prop->expr->type != E_SYMBOL)
prop_warn(prop,
"default for config symbol '%s'"
" must be a single symbol", sym->name);
if (prop->expr->type != E_SYMBOL)
break;
sym2 = prop_get_symbol(prop);
if (sym->type == S_HEX || sym->type == S_INT) {
if (!menu_validate_number(sym, sym2))
prop_warn(prop,
"'%s': number is invalid",
sym->name);
}
break;
case P_SELECT:
sym2 = prop_get_symbol(prop);
if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
prop_warn(prop,
"config symbol '%s' uses select, but is "
"not boolean or tristate", sym->name);
else if (sym2->type != S_UNKNOWN &&
sym2->type != S_BOOLEAN &&
sym2->type != S_TRISTATE)
prop_warn(prop,
"'%s' has wrong type. 'select' only "
"accept arguments of boolean and "
"tristate type", sym2->name);
break;
case P_RANGE:
if (sym->type != S_INT && sym->type != S_HEX)
prop_warn(prop, "range is only allowed "
"for int or hex symbols");
if (!menu_validate_number(sym, prop->expr->left.sym) ||
!menu_validate_number(sym, prop->expr->right.sym))
prop_warn(prop, "range is invalid");
break;
default:
;
}
}
}
void menu_finalize(struct menu *parent)
{
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
sym = parent->sym;
if (parent->list) {
if (sym && sym_is_choice(sym)) {
if (sym->type == S_UNKNOWN) {
/* find the first choice value to find out choice type */
current_entry = parent;
for (menu = parent->list; menu; menu = menu->next) {
if (menu->sym && menu->sym->type != S_UNKNOWN) {
menu_set_type(menu->sym->type);
break;
}
}
}
/* set the type of the remaining choice values */
for (menu = parent->list; menu; menu = menu->next) {
current_entry = menu;
if (menu->sym && menu->sym->type == S_UNKNOWN)
menu_set_type(sym->type);
}
parentdep = expr_alloc_symbol(sym);
} else if (parent->prompt)
parentdep = parent->prompt->visible.expr;
else
parentdep = parent->dep;
for (menu = parent->list; menu; menu = menu->next) {
basedep = expr_transform(menu->dep);
basedep = expr_alloc_and(expr_copy(parentdep), basedep);
basedep = expr_eliminate_dups(basedep);
menu->dep = basedep;
if (menu->sym)
prop = menu->sym->prop;
else
prop = menu->prompt;
for (; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
dep = expr_transform(prop->visible.expr);
dep = expr_alloc_and(expr_copy(basedep), dep);
dep = expr_eliminate_dups(dep);
if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep);
prop->visible.expr = dep;
if (prop->type == P_SELECT) {
struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
}
}
}
for (menu = parent->list; menu; menu = menu->next)
menu_finalize(menu);
} else if (sym) {
basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep));
last_menu = NULL;
for (menu = parent->next; menu; menu = menu->next) {
dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
if (!expr_contains_symbol(dep, sym))
break;
if (expr_depends_symbol(dep, sym))
goto next;
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
dep = expr_eliminate_dups(expr_transform(dep));
dep2 = expr_copy(basedep);
expr_eliminate_eq(&dep, &dep2);
expr_free(dep);
if (!expr_is_yes(dep2)) {
expr_free(dep2);
break;
}
expr_free(dep2);
next:
menu_finalize(menu);
menu->parent = parent;
last_menu = menu;
}
if (last_menu) {
parent->list = parent->next;
parent->next = last_menu->next;
last_menu->next = NULL;
}
sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
}
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) &&
menu->sym && !sym_is_choice_value(menu->sym)) {
current_entry = menu;
menu->sym->flags |= SYMBOL_CHOICEVAL;
if (!menu->prompt)
menu_warn(menu, "choice value must have a prompt");
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->type == P_DEFAULT)
prop_warn(prop, "defaults for choice "
"values not supported");
if (prop->menu == menu)
continue;
if (prop->type == P_PROMPT &&
prop->menu->parent->sym != sym)
prop_warn(prop, "choice value used outside its choice group");
}
/* Non-tristate choice values of tristate choices must
* depend on the choice being set to Y. The choice
* values' dependencies were propagated to their
* properties above, so the change here must be re-
* propagated.
*/
if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
menu->dep = expr_alloc_and(basedep, menu->dep);
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
prop->visible.expr = expr_alloc_and(expr_copy(basedep),
prop->visible.expr);
}
}
menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym);
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
;
*ep = expr_alloc_one(E_LIST, NULL);
(*ep)->right.sym = menu->sym;
}
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
for (last_menu = menu->list; ; last_menu = last_menu->next) {
last_menu->parent = parent;
if (!last_menu->next)
break;
}
last_menu->next = menu->next;
menu->next = menu->list;
menu->list = NULL;
}
}
if (sym && !(sym->flags & SYMBOL_WARNED)) {
if (sym->type == S_UNKNOWN)
menu_warn(parent, "config symbol defined without type");
if (sym_is_choice(sym) && !parent->prompt)
menu_warn(parent, "choice must have a prompt");
/* Check properties connected to this symbol */
sym_check_prop(sym);
sym->flags |= SYMBOL_WARNED;
}
if (sym && !sym_is_optional(sym) && parent->prompt) {
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
expr_alloc_and(parent->prompt->visible.expr,
expr_alloc_symbol(&symbol_mod)));
}
}
bool menu_has_prompt(struct menu *menu)
{
if (!menu->prompt)
return false;
return true;
}
/*
* Determine if a menu is empty.
* A menu is considered empty if it contains no or only
* invisible entries.
*/
bool menu_is_empty(struct menu *menu)
{
struct menu *child;
for (child = menu->list; child; child = child->next) {
if (menu_is_visible(child))
return(false);
}
return(true);
}
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
struct symbol *sym;
tristate visible;
if (!menu->prompt)
return false;
if (menu->visibility) {
if (expr_calc_value(menu->visibility) == no)
return false;
}
sym = menu->sym;
if (sym) {
sym_calc_value(sym);
visible = menu->prompt->visible.tri;
} else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
if (visible != no)
return true;
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
for (child = menu->list; child; child = child->next) {
if (menu_is_visible(child)) {
if (sym)
sym->flags |= SYMBOL_DEF_USER;
return true;
}
}
return false;
}
const char *menu_get_prompt(struct menu *menu)
{
if (menu->prompt)
return menu->prompt->text;
else if (menu->sym)
return menu->sym->name;
return NULL;
}
struct menu *menu_get_root_menu(struct menu *menu)
{
return &rootmenu;
}
struct menu *menu_get_parent_menu(struct menu *menu)
{
enum prop_type type;
for (; menu != &rootmenu; menu = menu->parent) {
type = menu->prompt ? menu->prompt->type : 0;
if (type == P_MENU)
break;
}
return menu;
}
bool menu_has_help(struct menu *menu)
{
return menu->help != NULL;
}
const char *menu_get_help(struct menu *menu)
{
if (menu->help)
return menu->help;
else
return "";
}
static void get_prompt_str(struct gstr *r, struct property *prop,
struct list_head *head)
{
int i, j;
struct menu *submenu[8], *menu, *location = NULL;
struct jump_key *jump = NULL;
str_printf(r, _("Prompt: %s\n"), _(prop->text));
menu = prop->menu->parent;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
bool accessible = menu_is_visible(menu);
submenu[i++] = menu;
if (location == NULL && accessible)
location = menu;
}
if (head && location) {
jump = xmalloc(sizeof(struct jump_key));
if (menu_is_visible(prop->menu)) {
/*
* There is not enough room to put the hint at the
* beginning of the "Prompt" line. Put the hint on the
* last "Location" line even when it would belong on
* the former.
*/
jump->target = prop->menu;
} else
jump->target = location;
if (list_empty(head))
jump->index = 0;
else
jump->index = list_entry(head->prev, struct jump_key,
entries)->index + 1;
list_add_tail(&jump->entries, head);
}
if (i > 0) {
str_printf(r, _(" Location:\n"));
for (j = 4; --i >= 0; j += 2) {
menu = submenu[i];
if (jump && menu == location)
jump->offset = strlen(r->s);
str_printf(r, "%*c-> %s", j, ' ',
_(menu_get_prompt(menu)));
if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : _("<choice>"),
sym_get_string_value(menu->sym));
}
str_append(r, "\n");
}
}
}
/*
* get property of type P_SYMBOL
*/
static struct property *get_symbol_prop(struct symbol *sym)
{
struct property *prop = NULL;
for_all_properties(sym, prop, P_SYMBOL)
break;
return prop;
}
/*
* head is optional and may be NULL
*/
static void get_symbol_str(struct gstr *r, struct symbol *sym,
struct list_head *head)
{
bool hit;
struct property *prop;
if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
sym_get_string_value(sym));
str_printf(r, "Type : %s\n", sym_type_name(sym->type));
if (sym->type == S_INT || sym->type == S_HEX) {
prop = sym_get_range_prop(sym);
if (prop) {
str_printf(r, "Range : ");
expr_gstr_print(prop->expr, r);
str_append(r, "\n");
}
}
}
for_all_prompts(sym, prop)
get_prompt_str(r, prop, head);
prop = get_symbol_prop(sym);
if (prop) {
str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
prop->menu->lineno);
if (!expr_is_yes(prop->visible.expr)) {
str_append(r, _(" Depends on: "));
expr_gstr_print(prop->visible.expr, r);
str_append(r, "\n");
}
}
hit = false;
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
str_append(r, " Selects: ");
hit = true;
} else
str_printf(r, " && ");
expr_gstr_print(prop->expr, r);
}
if (hit)
str_append(r, "\n");
if (sym->rev_dep.expr) {
str_append(r, _(" Selected by: "));
expr_gstr_print(sym->rev_dep.expr, r);
str_append(r, "\n");
}
str_append(r, "\n\n");
}
struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
{
struct symbol *sym;
struct gstr res = str_new();
int i;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
get_symbol_str(&res, sym, head);
if (!i)
str_append(&res, _("No matches found.\n"));
return res;
}
void menu_get_ext_help(struct menu *menu, struct gstr *help)
{
struct symbol *sym = menu->sym;
const char *help_text = nohelp_text;
if (menu_has_help(menu)) {
if (sym->name)
str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
help_text = menu_get_help(menu);
}
str_printf(help, "%s\n", _(help_text));
if (sym)
get_symbol_str(help, sym, NULL);
}

1870
scripts/config/qconf.cc Normal file

File diff suppressed because it is too large Load Diff

330
scripts/config/qconf.h Normal file
View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <QTextBrowser>
#include <QTreeWidget>
#include <QMainWindow>
#include <QHeaderView>
#include <qsettings.h>
#include <QPushButton>
#include <QSettings>
#include <QLineEdit>
#include <QSplitter>
#include <QCheckBox>
#include <QDialog>
#include "expr.h"
class ConfigView;
class ConfigList;
class ConfigItem;
class ConfigLineEdit;
class ConfigMainWindow;
class ConfigSettings : public QSettings {
public:
ConfigSettings();
QList<int> readSizes(const QString& key, bool *ok);
bool writeSizes(const QString& key, const QList<int>& value);
};
enum colIdx {
promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
};
enum listMode {
singleMode, menuMode, symbolMode, fullMode, listMode
};
enum optionMode {
normalOpt = 0, allOpt, promptOpt
};
class ConfigList : public QTreeWidget {
Q_OBJECT
typedef class QTreeWidget Parent;
public:
ConfigList(ConfigView* p, const char *name = 0);
void reinit(void);
ConfigView* parent(void) const
{
return (ConfigView*)Parent::parent();
}
ConfigItem* findConfigItem(struct menu *);
protected:
void keyPressEvent(QKeyEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseDoubleClickEvent(QMouseEvent *e);
void focusInEvent(QFocusEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
public slots:
void setRootMenu(struct menu *menu);
void updateList(ConfigItem *item);
void setValue(ConfigItem* item, tristate val);
void changeValue(ConfigItem* item);
void updateSelection(void);
void saveSettings(void);
signals:
void menuChanged(struct menu *menu);
void menuSelected(struct menu *menu);
void parentSelected(void);
void gotFocus(struct menu *);
public:
void updateListAll(void)
{
updateAll = true;
updateList(NULL);
updateAll = false;
}
ConfigList* listView()
{
return this;
}
ConfigItem* firstChild() const
{
return (ConfigItem *)children().first();
}
void addColumn(colIdx idx)
{
showColumn(idx);
}
void removeColumn(colIdx idx)
{
hideColumn(idx);
}
void setAllOpen(bool open);
void setParentMenu(void);
bool menuSkip(struct menu *);
void updateMenuList(ConfigItem *parent, struct menu*);
void updateMenuList(ConfigList *parent, struct menu*);
bool updateAll;
QPixmap symbolYesPix, symbolModPix, symbolNoPix;
QPixmap choiceYesPix, choiceNoPix;
QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
bool showName, showRange, showData;
enum listMode mode;
enum optionMode optMode;
struct menu *rootEntry;
QPalette disabledColorGroup;
QPalette inactivedColorGroup;
QMenu* headerPopup;
};
class ConfigItem : public QTreeWidgetItem {
typedef class QTreeWidgetItem Parent;
public:
ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
{
init();
}
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
: Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
{
init();
}
ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
: Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
{
init();
}
~ConfigItem(void);
void init(void);
void okRename(int col);
void updateMenu(void);
void testUpdateMenu(bool v);
ConfigList* listView() const
{
return (ConfigList*)Parent::treeWidget();
}
ConfigItem* firstChild() const
{
return (ConfigItem *)Parent::child(0);
}
ConfigItem* nextSibling()
{
ConfigItem *ret = NULL;
ConfigItem *_parent = (ConfigItem *)parent();
if(_parent) {
ret = (ConfigItem *)_parent->child(_parent->indexOfChild(this)+1);
} else {
QTreeWidget *_treeWidget = treeWidget();
ret = (ConfigItem *)_treeWidget->topLevelItem(_treeWidget->indexOfTopLevelItem(this)+1);
}
return ret;
}
void setText(colIdx idx, const QString& text)
{
Parent::setText(idx, text);
}
QString text(colIdx idx) const
{
return Parent::text(idx);
}
void setPixmap(colIdx idx, const QIcon &icon)
{
Parent::setIcon(idx, icon);
}
const QIcon pixmap(colIdx idx) const
{
return icon(idx);
}
// TODO: Implement paintCell
ConfigItem* nextItem;
struct menu *menu;
bool visible;
bool goParent;
};
class ConfigLineEdit : public QLineEdit {
Q_OBJECT
typedef class QLineEdit Parent;
public:
ConfigLineEdit(ConfigView* parent);
ConfigView* parent(void) const
{
return (ConfigView*)Parent::parent();
}
void show(ConfigItem *i);
void keyPressEvent(QKeyEvent *e);
public:
ConfigItem *item;
};
class ConfigView : public QWidget {
Q_OBJECT
typedef class QWidget Parent;
public:
ConfigView(QWidget* parent, const char *name = 0);
~ConfigView(void);
static void updateList(ConfigItem* item);
static void updateListAll(void);
bool showName(void) const { return list->showName; }
bool showRange(void) const { return list->showRange; }
bool showData(void) const { return list->showData; }
public slots:
void setShowName(bool);
void setShowRange(bool);
void setShowData(bool);
void setOptionMode(QAction *);
signals:
void showNameChanged(bool);
void showRangeChanged(bool);
void showDataChanged(bool);
public:
ConfigList* list;
ConfigLineEdit* lineEdit;
static ConfigView* viewList;
ConfigView* nextView;
static QAction *showNormalAction;
static QAction *showAllAction;
static QAction *showPromptAction;
};
class ConfigInfoView : public QTextBrowser {
Q_OBJECT
typedef class QTextBrowser Parent;
public:
ConfigInfoView(QWidget* parent, const char *name = 0);
bool showDebug(void) const { return _showDebug; }
public slots:
void setInfo(struct menu *menu);
void saveSettings(void);
void setShowDebug(bool);
signals:
void showDebugChanged(bool);
void menuSelected(struct menu *);
protected:
void symbolInfo(void);
void menuInfo(void);
QString debug_info(struct symbol *sym);
static QString print_filter(const QString &str);
static void expr_print_help(void *data, struct symbol *sym, const char *str);
QMenu *createStandardContextMenu(const QPoint & pos);
void contextMenuEvent(QContextMenuEvent *e);
struct symbol *sym;
struct menu *_menu;
bool _showDebug;
};
class ConfigSearchWindow : public QDialog {
Q_OBJECT
typedef class QDialog Parent;
public:
ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
public slots:
void saveSettings(void);
void search(void);
protected:
QLineEdit* editField;
QPushButton* searchButton;
QSplitter* split;
ConfigView* list;
ConfigInfoView* info;
struct symbol **result;
};
class ConfigMainWindow : public QMainWindow {
Q_OBJECT
static QAction *saveAction;
static void conf_changed(void);
public:
ConfigMainWindow(void);
public slots:
void changeMenu(struct menu *);
void setMenuLink(struct menu *);
void listFocusChanged(void);
void goBack(void);
void loadConfig(void);
bool saveConfig(void);
void saveConfigAs(void);
void searchConfig(void);
void showSingleView(void);
void showSplitView(void);
void showFullView(void);
void showIntro(void);
void showAbout(void);
void saveSettings(void);
protected:
void closeEvent(QCloseEvent *e);
ConfigSearchWindow *searchWindow;
ConfigView *menuView;
ConfigList *menuList;
ConfigView *configView;
ConfigList *configList;
ConfigInfoView *helpText;
QToolBar *toolBar;
QAction *backAction;
QAction *singleViewAction;
QAction *splitViewAction;
QAction *fullViewAction;
QSplitter *split1;
QSplitter *split2;
};

1386
scripts/config/symbol.c Normal file

File diff suppressed because it is too large Load Diff

147
scripts/config/util.c Normal file
View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
* Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "lkc.h"
/* file already present in list? If not add it */
struct file *file_lookup(const char *name)
{
struct file *file;
const char *file_name = sym_expand_string_value(name);
for (file = file_list; file; file = file->next) {
if (!strcmp(name, file->name)) {
free((void *)file_name);
return file;
}
}
file = xmalloc(sizeof(*file));
memset(file, 0, sizeof(*file));
file->name = file_name;
file->next = file_list;
file_list = file;
return file;
}
/* write a dependency file as used by kbuild to track dependencies */
int file_write_dep(const char *name)
{
struct symbol *sym, *env_sym;
struct expr *e;
struct file *file;
FILE *out;
if (!name)
name = ".kconfig.d";
out = fopen("..config.tmp", "w");
if (!out)
return 1;
fprintf(out, "deps_config := \\\n");
for (file = file_list; file; file = file->next) {
if (file->next)
fprintf(out, "\t%s \\\n", file->name);
else
fprintf(out, "\t%s\n", file->name);
}
fprintf(out, "\n%s: \\\n"
"\t$(deps_config)\n\n", conf_get_autoconfig_name());
expr_list_for_each_sym(sym_env_list, e, sym) {
struct property *prop;
const char *value;
prop = sym_get_env_prop(sym);
env_sym = prop_get_symbol(prop);
if (!env_sym)
continue;
value = getenv(env_sym->name);
if (!value)
value = "";
fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
fprintf(out, "endif\n");
}
fprintf(out, "\n$(deps_config): ;\n");
fclose(out);
rename("..config.tmp", name);
return 0;
}
/* Allocate initial growable string */
struct gstr str_new(void)
{
struct gstr gs;
gs.s = xmalloc(sizeof(char) * 64);
gs.len = 64;
gs.max_width = 0;
strcpy(gs.s, "\0");
return gs;
}
/* Free storage for growable string */
void str_free(struct gstr *gs)
{
if (gs->s)
free(gs->s);
gs->s = NULL;
gs->len = 0;
}
/* Append to growable string */
void str_append(struct gstr *gs, const char *s)
{
size_t l;
if (s) {
l = strlen(gs->s) + strlen(s) + 1;
if (l > gs->len) {
gs->s = realloc(gs->s, l);
gs->len = l;
}
strcat(gs->s, s);
}
}
/* Append printf formatted string to growable string */
void str_printf(struct gstr *gs, const char *fmt, ...)
{
va_list ap;
char s[10000]; /* big enough... */
va_start(ap, fmt);
vsnprintf(s, sizeof(s), fmt, ap);
str_append(gs, s);
va_end(ap);
}
/* Retrieve value of growable string */
const char *str_get(struct gstr *gs)
{
return gs->s;
}
void *xmalloc(size_t size)
{
void *p = malloc(size);
if (p)
return p;
fprintf(stderr, "Out of memory.\n");
exit(1);
}
void *xcalloc(size_t nmemb, size_t size)
{
void *p = calloc(nmemb, size);
if (p)
return p;
fprintf(stderr, "Out of memory.\n");
exit(1);
}

View File

@@ -0,0 +1,49 @@
%language=ANSI-C
%define hash-function-name kconf_id_hash
%define lookup-function-name kconf_id_lookup
%define string-pool-name kconf_id_strings
%compare-strncmp
%enum
%pic
%struct-type
struct kconf_id;
%%
mainmenu, T_MAINMENU, TF_COMMAND
menu, T_MENU, TF_COMMAND
endmenu, T_ENDMENU, TF_COMMAND
source, T_SOURCE, TF_COMMAND
choice, T_CHOICE, TF_COMMAND
endchoice, T_ENDCHOICE, TF_COMMAND
comment, T_COMMENT, TF_COMMAND
config, T_CONFIG, TF_COMMAND
menuconfig, T_MENUCONFIG, TF_COMMAND
help, T_HELP, TF_COMMAND
---help---, T_HELP, TF_COMMAND
if, T_IF, TF_COMMAND|TF_PARAM
endif, T_ENDIF, TF_COMMAND
depends, T_DEPENDS, TF_COMMAND
optional, T_OPTIONAL, TF_COMMAND
default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
prompt, T_PROMPT, TF_COMMAND
tristate, T_TYPE, TF_COMMAND, S_TRISTATE
def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
bool, T_TYPE, TF_COMMAND, S_BOOLEAN
boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
int, T_TYPE, TF_COMMAND, S_INT
hex, T_TYPE, TF_COMMAND, S_HEX
string, T_TYPE, TF_COMMAND, S_STRING
select, T_SELECT, TF_COMMAND
range, T_RANGE, TF_COMMAND
visible, T_VISIBLE, TF_COMMAND
option, T_OPTION, TF_COMMAND
on, T_ON, TF_PARAM
modules, T_OPT_MODULES, TF_OPTION
defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
env, T_OPT_ENV, TF_OPTION
allnoconfig_y, T_OPT_ALLNOCONFIG_Y,TF_OPTION
reset, T_RESET, TF_COMMAND
%%

View File

@@ -0,0 +1,250 @@
/* ANSI-C code produced by gperf version 3.0.4 */
/* Command-line: gperf */
/* Computed positions: -k'1,3' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
#endif
struct kconf_id;
/* maximum key range = 47, duplicates = 0 */
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
kconf_id_hash (register const char *str, register unsigned int len)
{
static unsigned char asso_values[] =
{
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 10, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 20, 40, 5,
0, 0, 5, 49, 5, 20, 49, 49, 5, 20,
5, 0, 35, 49, 0, 15, 0, 10, 15, 49,
25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49
};
register int hval = len;
switch (hval)
{
default:
hval += asso_values[(unsigned char)str[2]];
/*FALLTHROUGH*/
case 2:
case 1:
hval += asso_values[(unsigned char)str[0]];
break;
}
return hval;
}
struct kconf_id_strings_t
{
char kconf_id_strings_str2[sizeof("on")];
char kconf_id_strings_str5[sizeof("endif")];
char kconf_id_strings_str6[sizeof("option")];
char kconf_id_strings_str7[sizeof("endmenu")];
char kconf_id_strings_str8[sizeof("optional")];
char kconf_id_strings_str9[sizeof("endchoice")];
char kconf_id_strings_str10[sizeof("range")];
char kconf_id_strings_str11[sizeof("choice")];
char kconf_id_strings_str12[sizeof("default")];
char kconf_id_strings_str13[sizeof("def_bool")];
char kconf_id_strings_str14[sizeof("help")];
char kconf_id_strings_str16[sizeof("config")];
char kconf_id_strings_str17[sizeof("def_tristate")];
char kconf_id_strings_str18[sizeof("env")];
char kconf_id_strings_str19[sizeof("defconfig_list")];
char kconf_id_strings_str20[sizeof("reset")];
char kconf_id_strings_str21[sizeof("string")];
char kconf_id_strings_str22[sizeof("if")];
char kconf_id_strings_str23[sizeof("int")];
char kconf_id_strings_str26[sizeof("select")];
char kconf_id_strings_str27[sizeof("modules")];
char kconf_id_strings_str28[sizeof("tristate")];
char kconf_id_strings_str29[sizeof("menu")];
char kconf_id_strings_str30[sizeof("---help---")];
char kconf_id_strings_str31[sizeof("source")];
char kconf_id_strings_str32[sizeof("comment")];
char kconf_id_strings_str33[sizeof("hex")];
char kconf_id_strings_str35[sizeof("menuconfig")];
char kconf_id_strings_str37[sizeof("visible")];
char kconf_id_strings_str38[sizeof("allnoconfig_y")];
char kconf_id_strings_str41[sizeof("prompt")];
char kconf_id_strings_str42[sizeof("depends")];
char kconf_id_strings_str44[sizeof("bool")];
char kconf_id_strings_str47[sizeof("boolean")];
char kconf_id_strings_str48[sizeof("mainmenu")];
};
static struct kconf_id_strings_t kconf_id_strings_contents =
{
"on",
"endif",
"option",
"endmenu",
"optional",
"endchoice",
"range",
"choice",
"default",
"def_bool",
"help",
"config",
"def_tristate",
"env",
"defconfig_list",
"reset",
"string",
"if",
"int",
"select",
"modules",
"tristate",
"menu",
"---help---",
"source",
"comment",
"hex",
"menuconfig",
"visible",
"allnoconfig_y",
"prompt",
"depends",
"bool",
"boolean",
"mainmenu"
};
#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
#ifdef __GNUC__
__inline
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
__attribute__ ((__gnu_inline__))
#endif
#endif
struct kconf_id *
kconf_id_lookup (register const char *str, register unsigned int len)
{
enum
{
TOTAL_KEYWORDS = 35,
MIN_WORD_LENGTH = 2,
MAX_WORD_LENGTH = 14,
MIN_HASH_VALUE = 2,
MAX_HASH_VALUE = 48
};
static struct kconf_id wordlist[] =
{
{-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_ON, TF_PARAM},
{-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_OPTION, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_OPTIONAL, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_CHOICE, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND},
{-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPT_ENV, TF_OPTION},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_RESET, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_TYPE, TF_COMMAND, S_STRING},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT},
{-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SELECT, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str30, T_HELP, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SOURCE, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_HEX},
{-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND},
{-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_VISIBLE, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str38, T_OPT_ALLNOCONFIG_Y,TF_OPTION},
{-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_PROMPT, TF_COMMAND},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_DEPENDS, TF_COMMAND},
{-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44, T_TYPE, TF_COMMAND, S_BOOLEAN},
{-1}, {-1},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = kconf_id_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
register int o = wordlist[key].name;
if (o >= 0)
{
register const char *s = o + kconf_id_strings;
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
return &wordlist[key];
}
}
}
return 0;
}

427
scripts/config/zconf.l Normal file
View File

@@ -0,0 +1,427 @@
%option nostdinit noyywrap never-interactive full ecs
%option 8bit nodefault perf-report perf-report
%option noinput
%x COMMAND HELP STRING PARAM
%{
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glob.h>
#include <libgen.h>
#include "lkc.h"
#define START_STRSIZE 16
static struct {
struct file *file;
int lineno;
} current_pos;
static char *text;
static int text_size, text_asize;
struct buffer {
struct buffer *parent;
YY_BUFFER_STATE state;
};
struct buffer *current_buf;
static int last_ts, first_ts;
static void zconf_endhelp(void);
static void zconf_endfile(void);
static void new_string(void)
{
text = xmalloc(START_STRSIZE);
text_asize = START_STRSIZE;
text_size = 0;
*text = 0;
}
static void append_string(const char *str, int size)
{
int new_size = text_size + size + 1;
if (new_size > text_asize) {
new_size += START_STRSIZE - 1;
new_size &= -START_STRSIZE;
text = realloc(text, new_size);
text_asize = new_size;
}
memcpy(text + text_size, str, size);
text_size += size;
text[text_size] = 0;
}
static void alloc_string(const char *str, int size)
{
text = xmalloc(size + 1);
memcpy(text, str, size);
text[size] = 0;
}
static void warn_ignored_character(char chr)
{
fprintf(stderr,
"%s:%d:warning: ignoring unsupported character '%c'\n",
zconf_curname(), zconf_lineno(), chr);
}
%}
n [A-Za-z0-9_-]
%%
int str = 0;
int ts, i;
[ \t]*#.*\n |
[ \t]*\n {
current_file->lineno++;
return T_EOL;
}
[ \t]*#.*
[ \t]+ {
BEGIN(COMMAND);
}
. {
unput(yytext[0]);
BEGIN(COMMAND);
}
<COMMAND>{
{n}+ {
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
BEGIN(PARAM);
current_pos.file = current_file;
current_pos.lineno = current_file->lineno;
if (id && id->flags & TF_COMMAND) {
zconflval.id = id;
return id->token;
}
alloc_string(yytext, yyleng);
zconflval.string = text;
return T_WORD;
}
. warn_ignored_character(*yytext);
\n {
BEGIN(INITIAL);
current_file->lineno++;
return T_EOL;
}
}
<PARAM>{
"&&" return T_AND;
"||" return T_OR;
"(" return T_OPEN_PAREN;
")" return T_CLOSE_PAREN;
"!" return T_NOT;
"=" return T_EQUAL;
"!=" return T_UNEQUAL;
"<=" return T_LESS_EQUAL;
">=" return T_GREATER_EQUAL;
"<" return T_LESS;
">" return T_GREATER;
\"|\' {
str = yytext[0];
new_string();
BEGIN(STRING);
}
\n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
({n}|[/.])+ {
const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
if (id && id->flags & TF_PARAM) {
zconflval.id = id;
return id->token;
}
alloc_string(yytext, yyleng);
zconflval.string = text;
return T_WORD;
}
#.* /* comment */
\\\n current_file->lineno++;
[[:blank:]]+
. warn_ignored_character(*yytext);
<<EOF>> {
BEGIN(INITIAL);
}
}
<STRING>{
[^'"\\\n]+/\n {
append_string(yytext, yyleng);
zconflval.string = text;
return T_WORD_QUOTE;
}
[^'"\\\n]+ {
append_string(yytext, yyleng);
}
\\.?/\n {
append_string(yytext + 1, yyleng - 1);
zconflval.string = text;
return T_WORD_QUOTE;
}
\\.? {
append_string(yytext + 1, yyleng - 1);
}
\'|\" {
if (str == yytext[0]) {
BEGIN(PARAM);
zconflval.string = text;
return T_WORD_QUOTE;
} else
append_string(yytext, 1);
}
\n {
printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
current_file->lineno++;
BEGIN(INITIAL);
return T_EOL;
}
<<EOF>> {
BEGIN(INITIAL);
}
}
<HELP>{
[ \t]+ {
ts = 0;
for (i = 0; i < yyleng; i++) {
if (yytext[i] == '\t')
ts = (ts & ~7) + 8;
else
ts++;
}
last_ts = ts;
if (first_ts) {
if (ts < first_ts) {
zconf_endhelp();
return T_HELPTEXT;
}
ts -= first_ts;
while (ts > 8) {
append_string(" ", 8);
ts -= 8;
}
append_string(" ", ts);
}
}
[ \t]*\n/[^ \t\n] {
current_file->lineno++;
zconf_endhelp();
return T_HELPTEXT;
}
[ \t]*\n {
current_file->lineno++;
append_string("\n", 1);
}
[^ \t\n].* {
while (yyleng) {
if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
break;
yyleng--;
}
append_string(yytext, yyleng);
if (!first_ts)
first_ts = last_ts;
}
<<EOF>> {
zconf_endhelp();
return T_HELPTEXT;
}
}
<<EOF>> {
if (current_file) {
zconf_endfile();
return T_EOL;
}
fclose(yyin);
yyterminate();
}
%%
void zconf_starthelp(void)
{
new_string();
last_ts = first_ts = 0;
BEGIN(HELP);
}
static void zconf_endhelp(void)
{
zconflval.string = text;
BEGIN(INITIAL);
}
/*
* Try to open specified file with following names:
* ./name
* $(srctree)/name
* The latter is used when srctree is separate from objtree
* when compiling the kernel.
* Return NULL if file is not found.
*/
FILE *zconf_fopen(const char *name)
{
char *env, fullname[PATH_MAX+1];
FILE *f;
f = fopen(name, "r");
if (!f && name != NULL && name[0] != '/') {
env = getenv(SRCTREE);
if (env) {
sprintf(fullname, "%s/%s", env, name);
f = fopen(fullname, "r");
}
}
return f;
}
void zconf_initscan(const char *name)
{
yyin = zconf_fopen(name);
if (!yyin) {
printf("can't find file %s\n", name);
exit(1);
}
current_buf = xmalloc(sizeof(*current_buf));
memset(current_buf, 0, sizeof(*current_buf));
current_file = file_lookup(name);
current_file->lineno = 1;
}
static void __zconf_nextfile(const char *name)
{
struct file *iter;
struct file *file = file_lookup(name);
struct buffer *buf = xmalloc(sizeof(*buf));
memset(buf, 0, sizeof(*buf));
current_buf->state = YY_CURRENT_BUFFER;
yyin = zconf_fopen(file->name);
if (!yyin) {
printf("%s:%d: can't open file \"%s\"\n",
zconf_curname(), zconf_lineno(), file->name);
exit(1);
}
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
buf->parent = current_buf;
current_buf = buf;
for (iter = current_file->parent; iter; iter = iter->parent ) {
if (!strcmp(current_file->name,iter->name) ) {
printf("%s:%d: recursive inclusion detected. "
"Inclusion path:\n current file : '%s'\n",
zconf_curname(), zconf_lineno(),
zconf_curname());
iter = current_file->parent;
while (iter && \
strcmp(iter->name,current_file->name)) {
printf(" included from: '%s:%d'\n",
iter->name, iter->lineno-1);
iter = iter->parent;
}
if (iter)
printf(" included from: '%s:%d'\n",
iter->name, iter->lineno+1);
exit(1);
}
}
file->lineno = 1;
file->parent = current_file;
current_file = file;
}
void zconf_nextfile(const char *name)
{
glob_t gl;
int err;
int i;
char path[PATH_MAX], *p;
err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
/* ignore wildcard patterns that return no result */
if (err == GLOB_NOMATCH && strchr(name, '*')) {
err = 0;
gl.gl_pathc = 0;
}
if (err == GLOB_NOMATCH) {
p = strdup(current_file->name);
if (p) {
snprintf(path, sizeof(path), "%s/%s", dirname(p), name);
err = glob(path, GLOB_ERR | GLOB_MARK, NULL, &gl);
free(p);
}
}
if (err) {
const char *reason = "unknown error";
switch (err) {
case GLOB_NOSPACE:
reason = "out of memory";
break;
case GLOB_ABORTED:
reason = "read error";
break;
case GLOB_NOMATCH:
reason = "No files found";
break;
default:
break;
}
printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
reason, name);
exit(1);
}
for (i = 0; i < gl.gl_pathc; i++)
__zconf_nextfile(gl.gl_pathv[i]);
}
static void zconf_endfile(void)
{
struct buffer *parent;
current_file = current_file->parent;
parent = current_buf->parent;
if (parent) {
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(parent->state);
}
free(current_buf);
current_buf = parent;
}
int zconf_lineno(void)
{
return current_pos.lineno;
}
const char *zconf_curname(void)
{
return current_pos.file ? current_pos.file->name : "<none>";
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

754
scripts/config/zconf.y Normal file
View File

@@ -0,0 +1,754 @@
%{
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "lkc.h"
#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
#define PRINTD 0x0001
#define DEBUG_PARSE 0x0002
int cdebug = PRINTD;
extern int zconflex(void);
static void zconfprint(const char *err, ...);
static void zconf_error(const char *err, ...);
static void zconferror(const char *err);
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
struct symbol *symbol_hash[SYMBOL_HASHSIZE];
static struct menu *current_menu, *current_entry;
%}
%expect 30
%union
{
char *string;
struct file *file;
struct symbol *symbol;
struct expr *expr;
struct menu *menu;
const struct kconf_id *id;
}
%token <id>T_MAINMENU
%token <id>T_MENU
%token <id>T_ENDMENU
%token <id>T_SOURCE
%token <id>T_CHOICE
%token <id>T_ENDCHOICE
%token <id>T_COMMENT
%token <id>T_CONFIG
%token <id>T_MENUCONFIG
%token <id>T_HELP
%token <string> T_HELPTEXT
%token <id>T_IF
%token <id>T_ENDIF
%token <id>T_DEPENDS
%token <id>T_OPTIONAL
%token <id>T_PROMPT
%token <id>T_TYPE
%token <id>T_DEFAULT
%token <id>T_SELECT
%token <id>T_RANGE
%token <id>T_VISIBLE
%token <id>T_OPTION
%token <id>T_ON
%token <id>T_RESET
%token <string> T_WORD
%token <string> T_WORD_QUOTE
%token T_UNEQUAL
%token T_LESS
%token T_LESS_EQUAL
%token T_GREATER
%token T_GREATER_EQUAL
%token T_CLOSE_PAREN
%token T_OPEN_PAREN
%token T_EOL
%left T_OR
%left T_AND
%left T_EQUAL T_UNEQUAL
%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
%nonassoc T_NOT
%type <string> prompt
%type <symbol> symbol
%type <expr> expr
%type <expr> if_expr
%type <id> end
%type <id> option_name
%type <menu> if_entry menu_entry choice_entry
%type <string> symbol_option_arg word_opt
%destructor {
fprintf(stderr, "%s:%d: missing end statement for this entry\n",
$$->file->name, $$->lineno);
if (current_menu == $$)
menu_end_menu();
} if_entry menu_entry choice_entry
%{
/* Include zconf.hash.c here so it can see the token constants. */
#include "zconf.hash.c"
%}
%%
input: nl start | start;
start: mainmenu_stmt stmt_list | stmt_list;
stmt_list:
/* empty */
| stmt_list common_stmt
| stmt_list choice_stmt
| stmt_list menu_stmt
| stmt_list end { zconf_error("unexpected end statement"); }
| stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
| stmt_list option_name error T_EOL
{
zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
}
| stmt_list error T_EOL { zconf_error("invalid statement"); }
;
option_name:
T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE | T_RESET
;
common_stmt:
T_EOL
| if_stmt
| comment_stmt
| config_stmt
| menuconfig_stmt
| source_stmt
;
option_error:
T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
| error T_EOL { zconf_error("invalid option"); }
;
/* config/menuconfig entry */
config_entry_start: T_CONFIG T_WORD T_EOL
{
struct symbol *sym = sym_lookup($2, 0);
sym->flags |= SYMBOL_OPTIONAL;
menu_add_entry(sym);
printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
};
config_stmt: config_entry_start config_option_list
{
menu_end_entry();
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
};
menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
{
struct symbol *sym = sym_lookup($2, 0);
sym->flags |= SYMBOL_OPTIONAL;
menu_add_entry(sym);
printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
};
menuconfig_stmt: menuconfig_entry_start config_option_list
{
if (current_entry->prompt)
current_entry->prompt->type = P_MENU;
else
zconfprint("warning: menuconfig statement without prompt");
menu_end_entry();
printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
};
config_option_list:
/* empty */
| config_option_list config_option
| config_option_list symbol_option
| config_option_list depends
| config_option_list help
| config_option_list option_error
| config_option_list T_EOL
;
config_option: T_TYPE prompt_stmt_opt T_EOL
{
menu_set_type($1->stype);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(),
$1->stype);
};
config_option: T_PROMPT prompt if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
};
config_option: T_DEFAULT expr if_expr T_EOL
{
menu_add_expr(P_DEFAULT, $2, $3);
if ($1->stype != S_UNKNOWN)
menu_set_type($1->stype);
printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
zconf_curname(), zconf_lineno(),
$1->stype);
};
config_option: T_SELECT T_WORD if_expr T_EOL
{
menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
};
config_option: T_RANGE symbol symbol if_expr T_EOL
{
menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
};
symbol_option: T_OPTION symbol_option_list T_EOL
;
symbol_option_list:
/* empty */
| symbol_option_list T_WORD symbol_option_arg
{
const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
if (id && id->flags & TF_OPTION)
menu_add_option(id->token, $3);
else
zconfprint("warning: ignoring unknown option %s", $2);
free($2);
};
symbol_option_arg:
/* empty */ { $$ = NULL; }
| T_EQUAL prompt { $$ = $2; }
;
/* choice entry */
choice: T_CHOICE word_opt T_EOL
{
struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
sym->flags |= SYMBOL_AUTO;
menu_add_entry(sym);
menu_add_expr(P_CHOICE, NULL, NULL);
printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
};
choice_entry: choice choice_option_list
{
$$ = menu_add_menu();
};
choice_end: end
{
if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
}
};
choice_stmt: choice_entry choice_block choice_end
;
choice_option_list:
/* empty */
| choice_option_list choice_option
| choice_option_list depends
| choice_option_list help
| choice_option_list T_EOL
| choice_option_list option_error
;
choice_option: T_PROMPT prompt if_expr T_EOL
{
menu_add_prompt(P_PROMPT, $2, $3);
printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
};
choice_option: T_TYPE prompt_stmt_opt T_EOL
{
if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
menu_set_type($1->stype);
printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
zconf_curname(), zconf_lineno(),
$1->stype);
} else
YYERROR;
};
choice_option: T_OPTIONAL T_EOL
{
current_entry->sym->flags |= SYMBOL_OPTIONAL;
printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
};
choice_option: T_RESET if_expr T_EOL
{
menu_add_prop(P_RESET, NULL, NULL, $2);
};
choice_option: T_DEFAULT T_WORD if_expr T_EOL
{
if ($1->stype == S_UNKNOWN) {
menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
printd(DEBUG_PARSE, "%s:%d:default\n",
zconf_curname(), zconf_lineno());
} else
YYERROR;
};
choice_block:
/* empty */
| choice_block common_stmt
;
/* if entry */
if_entry: T_IF expr nl
{
printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
menu_add_entry(NULL);
menu_add_dep($2);
$$ = menu_add_menu();
};
if_end: end
{
if (zconf_endtoken($1, T_IF, T_ENDIF)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
}
};
if_stmt: if_entry if_block if_end
;
if_block:
/* empty */
| if_block common_stmt
| if_block menu_stmt
| if_block choice_stmt
;
/* mainmenu entry */
mainmenu_stmt: T_MAINMENU prompt nl
{
menu_add_prompt(P_MENU, $2, NULL);
};
/* menu entry */
menu: T_MENU prompt T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_MENU, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
};
menu_entry: menu visibility_list depends_list
{
$$ = menu_add_menu();
};
menu_end: end
{
if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
menu_end_menu();
printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
}
};
menu_stmt: menu_entry menu_block menu_end
;
menu_block:
/* empty */
| menu_block common_stmt
| menu_block menu_stmt
| menu_block choice_stmt
;
source_stmt: T_SOURCE prompt T_EOL
{
printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
zconf_nextfile($2);
};
/* comment entry */
comment: T_COMMENT prompt T_EOL
{
menu_add_entry(NULL);
menu_add_prompt(P_COMMENT, $2, NULL);
printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
};
comment_stmt: comment depends_list
{
menu_end_entry();
};
/* help option */
help_start: T_HELP T_EOL
{
printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
zconf_starthelp();
};
help: help_start T_HELPTEXT
{
current_entry->help = $2;
};
/* depends option */
depends_list:
/* empty */
| depends_list depends
| depends_list T_EOL
| depends_list option_error
;
depends: T_DEPENDS T_ON expr T_EOL
{
menu_add_dep($3);
printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
} | T_DEPENDS expr T_EOL
{
menu_add_dep($2);
zconfprint("warning: deprecated 'depends' syntax, use 'depends on' instead.");
};
/* visibility option */
visibility_list:
/* empty */
| visibility_list visible
| visibility_list T_EOL
;
visible: T_VISIBLE if_expr
{
menu_add_visibility($2);
};
/* prompt statement */
prompt_stmt_opt:
/* empty */
| prompt if_expr
{
menu_add_prompt(P_PROMPT, $1, $2);
};
prompt: T_WORD
| T_WORD_QUOTE
;
end: T_ENDMENU T_EOL { $$ = $1; }
| T_ENDCHOICE T_EOL { $$ = $1; }
| T_ENDIF T_EOL { $$ = $1; }
;
nl:
T_EOL
| nl T_EOL
;
if_expr: /* empty */ { $$ = NULL; }
| T_IF expr { $$ = $2; }
;
expr: symbol { $$ = expr_alloc_symbol($1); }
| symbol T_LESS symbol { $$ = expr_alloc_comp(E_LTH, $1, $3); }
| symbol T_LESS_EQUAL symbol { $$ = expr_alloc_comp(E_LEQ, $1, $3); }
| symbol T_GREATER symbol { $$ = expr_alloc_comp(E_GTH, $1, $3); }
| symbol T_GREATER_EQUAL symbol { $$ = expr_alloc_comp(E_GEQ, $1, $3); }
| symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
| symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
| T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
| T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
| expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
| expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
;
symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
| T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
;
word_opt: /* empty */ { $$ = NULL; }
| T_WORD
%%
void conf_parse(const char *name)
{
struct symbol *sym;
int i;
zconf_initscan(name);
sym_init();
_menu_init();
rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
#if YYDEBUG
if (getenv("ZCONF_DEBUG"))
zconfdebug = 1;
#endif
zconfparse();
if (zconfnerrs)
exit(1);
if (!modules_sym)
modules_sym = sym_find( "n" );
rootmenu.prompt->text = _(rootmenu.prompt->text);
rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
menu_finalize(&rootmenu);
for_all_symbols(i, sym) {
if (sym_check_deps(sym))
zconfnerrs++;
}
if (zconfnerrs)
exit(1);
sym_set_change_count(1);
}
static const char *zconf_tokenname(int token)
{
switch (token) {
case T_MENU: return "menu";
case T_ENDMENU: return "endmenu";
case T_CHOICE: return "choice";
case T_ENDCHOICE: return "endchoice";
case T_IF: return "if";
case T_ENDIF: return "endif";
case T_DEPENDS: return "depends";
case T_VISIBLE: return "visible";
}
return "<token>";
}
static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
{
if (id->token != endtoken) {
zconf_error("unexpected '%s' within %s block",
kconf_id_strings + id->name, zconf_tokenname(starttoken));
zconfnerrs++;
return false;
}
if (current_menu->file != current_file) {
zconf_error("'%s' in different file than '%s'",
kconf_id_strings + id->name, zconf_tokenname(starttoken));
fprintf(stderr, "%s:%d: location of the '%s'\n",
current_menu->file->name, current_menu->lineno,
zconf_tokenname(starttoken));
zconfnerrs++;
return false;
}
return true;
}
static void zconfprint(const char *err, ...)
{
va_list ap;
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
va_start(ap, err);
vfprintf(stderr, err, ap);
va_end(ap);
fprintf(stderr, "\n");
}
static void zconf_error(const char *err, ...)
{
va_list ap;
zconfnerrs++;
fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
va_start(ap, err);
vfprintf(stderr, err, ap);
va_end(ap);
fprintf(stderr, "\n");
}
static void zconferror(const char *err)
{
fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
}
static void print_quoted_string(FILE *out, const char *str)
{
const char *p;
int len;
putc('"', out);
while ((p = strchr(str, '"'))) {
len = p - str;
if (len)
fprintf(out, "%.*s", len, str);
fputs("\\\"", out);
str = p + 1;
}
fputs(str, out);
putc('"', out);
}
static void print_symbol(FILE *out, struct menu *menu)
{
struct symbol *sym = menu->sym;
struct property *prop;
if (sym_is_choice(sym))
fprintf(out, "\nchoice\n");
else
fprintf(out, "\nconfig %s\n", sym->name);
switch (sym->type) {
case S_BOOLEAN:
fputs(" boolean\n", out);
break;
case S_TRISTATE:
fputs(" tristate\n", out);
break;
case S_STRING:
fputs(" string\n", out);
break;
case S_INT:
fputs(" integer\n", out);
break;
case S_HEX:
fputs(" hex\n", out);
break;
default:
fputs(" ???\n", out);
break;
}
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
switch (prop->type) {
case P_PROMPT:
fputs(" prompt ", out);
print_quoted_string(out, prop->text);
if (!expr_is_yes(prop->visible.expr)) {
fputs(" if ", out);
expr_fprint(prop->visible.expr, out);
}
fputc('\n', out);
break;
case P_DEFAULT:
fputs( " default ", out);
expr_fprint(prop->expr, out);
if (!expr_is_yes(prop->visible.expr)) {
fputs(" if ", out);
expr_fprint(prop->visible.expr, out);
}
fputc('\n', out);
break;
case P_CHOICE:
fputs(" #choice value\n", out);
break;
case P_SELECT:
fputs( " select ", out);
expr_fprint(prop->expr, out);
fputc('\n', out);
break;
case P_RANGE:
fputs( " range ", out);
expr_fprint(prop->expr, out);
fputc('\n', out);
break;
case P_MENU:
fputs( " menu ", out);
print_quoted_string(out, prop->text);
fputc('\n', out);
break;
default:
fprintf(out, " unknown prop %d!\n", prop->type);
break;
}
}
if (menu->help) {
int len = strlen(menu->help);
while (menu->help[--len] == '\n')
menu->help[len] = 0;
fprintf(out, " help\n%s\n", menu->help);
}
}
void zconfdump(FILE *out)
{
struct property *prop;
struct symbol *sym;
struct menu *menu;
menu = rootmenu.list;
while (menu) {
if ((sym = menu->sym))
print_symbol(out, menu);
else if ((prop = menu->prompt)) {
switch (prop->type) {
case P_COMMENT:
fputs("\ncomment ", out);
print_quoted_string(out, prop->text);
fputs("\n", out);
break;
case P_MENU:
fputs("\nmenu ", out);
print_quoted_string(out, prop->text);
fputs("\n", out);
break;
default:
;
}
if (!expr_is_yes(prop->visible.expr)) {
fputs(" depends ", out);
expr_fprint(prop->visible.expr, out);
fputc('\n', out);
}
}
if (menu->list)
menu = menu->list;
else if (menu->next)
menu = menu->next;
else while ((menu = menu->parent)) {
if (menu->prompt && menu->prompt->type == P_MENU)
fputs("\nendmenu\n", out);
if (menu->next) {
menu = menu->next;
break;
}
}
}
}
#include "zconf.lex.c"
#include "util.c"
#include "confdata.c"
#include "expr.c"
#include "symbol.c"
#include "menu.c"

211
scripts/deptest.sh Executable file
View File

@@ -0,0 +1,211 @@
#!/usr/bin/env bash
#
# Automated OpenWrt package dependency checker
#
# Copyright (C) 2009-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
SCRIPTDIR="$(dirname "$0")"
[ "${SCRIPTDIR:0:1}" = "/" ] || SCRIPTDIR="$PWD/$SCRIPTDIR"
BASEDIR="$SCRIPTDIR/.."
DIR="$BASEDIR/tmp/deptest"
STAMP_DIR_SUCCESS="$DIR/stamp-success"
STAMP_DIR_FAILED="$DIR/stamp-failed"
STAMP_DIR_BLACKLIST="$DIR/stamp-blacklist"
BUILD_DIR="$DIR/build_dir/target"
BUILD_DIR_HOST="$DIR/build_dir/host"
KERNEL_BUILD_DIR="$DIR/build_dir/linux"
STAGING_DIR="$DIR/staging_dir/target"
STAGING_DIR_HOST="$DIR/staging_dir/host"
STAGING_DIR_HOST_TMPL="$DIR/staging_dir_host_tmpl"
BIN_DIR="$DIR/staging_dir/bin_dir"
LOG_DIR_NAME="logs"
LOG_DIR="$DIR/$LOG_DIR_NAME"
die()
{
echo "$@"
exit 1
}
usage()
{
echo "deptest.sh [OPTIONS] [PACKAGES]"
echo
echo "OPTIONS:"
echo " --lean Run a lean test. Do not clean the build directory for each"
echo " package test."
echo " --force Force a test, even if a success/blacklist stamp is available"
echo " -j X Number of make jobs"
echo
echo "PACKAGES are packages to test. If not specified, all installed packages"
echo "will be tested."
}
deptest_make()
{
local target="$1"
shift
local logfile="$1"
shift
make -j$nrjobs "$target" \
BUILD_DIR="$BUILD_DIR" \
BUILD_DIR_HOST="$BUILD_DIR_HOST" \
KERNEL_BUILD_DIR="$KERNEL_BUILD_DIR" \
BIN_DIR="$BIN_DIR" \
STAGING_DIR="$STAGING_DIR" \
STAGING_DIR_HOST="$STAGING_DIR_HOST" \
FORCE_HOST_INSTALL=1 \
V=99 "$@" >"$LOG_DIR/$logfile" 2>&1
}
clean_kernel_build_dir()
{
# delete everything, except the kernel build dir "linux-X.X.X"
(
cd "$KERNEL_BUILD_DIR" || die "Failed to enter kernel build dir"
for entry in *; do
[ -z "$(echo "$entry" | egrep -e '^linux-*.*.*$')" ] || continue
rm -rf "$entry" || die "Failed to clean kernel build dir"
done
)
}
stamp_exists() # $1=stamp
{
[ -e "$1" -o -L "$1" ]
}
test_package() # $1=pkgname
{
local pkg="$1"
[ -n "$pkg" -a -z "$(echo "$pkg" | grep -e '/')" -a "$pkg" != "." -a "$pkg" != ".." ] || \
die "Package name \"$pkg\" contains illegal characters"
local SELECTED=
for conf in `grep CONFIG_PACKAGE tmp/.packagedeps | grep -E "[ /]$pkg\$" | sed -e 's,package-$(\(CONFIG_PACKAGE_.*\)).*,\1,'`; do
grep "$conf=" .config > /dev/null && SELECTED=1 && break
done
local STAMP_SUCCESS="$STAMP_DIR_SUCCESS/$pkg"
local STAMP_FAILED="$STAMP_DIR_FAILED/$pkg"
local STAMP_BLACKLIST="$STAMP_DIR_BLACKLIST/$pkg"
rm -f "$STAMP_FAILED"
stamp_exists "$STAMP_SUCCESS" && [ $force -eq 0 ] && return
rm -f "$STAMP_SUCCESS"
[ -n "$SELECTED" ] || {
echo "Package $pkg is not selected"
return
}
stamp_exists "$STAMP_BLACKLIST" && [ $force -eq 0 ] && {
echo "Package $pkg is blacklisted"
return
}
echo "Testing package $pkg..."
rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST"
mkdir -p "$STAGING_DIR"
cp -al "$STAGING_DIR_HOST_TMPL" "$STAGING_DIR_HOST"
[ $lean_test -eq 0 ] && {
rm -rf "$BUILD_DIR" "$BUILD_DIR_HOST"
clean_kernel_build_dir
}
mkdir -p "$BUILD_DIR" "$BUILD_DIR_HOST"
local logfile="$(basename $pkg).log"
deptest_make "package/$pkg/compile" "$logfile"
if [ $? -eq 0 ]; then
( cd "$STAMP_DIR_SUCCESS"; ln -s "../$LOG_DIR_NAME/$logfile" "./$pkg" )
else
( cd "$STAMP_DIR_FAILED"; ln -s "../$LOG_DIR_NAME/$logfile" "./$pkg" )
echo "Building package $pkg FAILED"
fi
}
# parse commandline options
packages=
lean_test=0
force=0
nrjobs=1
while [ $# -ne 0 ]; do
case "$1" in
--help|-h)
usage
exit 0
;;
--lean)
lean_test=1
;;
--force)
force=1
;;
-j*)
if [ -n "${1:2}" ]; then
nrjobs="${1:2}"
else
shift
nrjobs="$1"
fi
;;
*)
packages="$packages $1"
;;
esac
shift
done
[ -f "$BASEDIR/include/toplevel.mk" ] || \
die "Error: Could not find buildsystem base directory"
[ -f "$BASEDIR/.config" ] || \
die "The buildsystem is not configured. Please run make menuconfig."
cd "$BASEDIR" || die "Failed to enter base directory"
mkdir -p "$STAMP_DIR_SUCCESS" "$STAMP_DIR_FAILED" "$STAMP_DIR_BLACKLIST" \
"$BIN_DIR" "$LOG_DIR"
bootstrap_deptest_make()
{
local target="$1"
shift
local logfile="bootstrap-deptest-$(echo "$target" | tr / -).log"
echo "deptest-make $target"
deptest_make "$target" "$logfile" "$@" || \
die "make $target failed, please check $logfile"
}
bootstrap_native_make()
{
local target="$1"
shift
local logfile="bootstrap-native-$(echo "$target" | tr / -).log"
echo "make $target"
make -j$nrjobs "$target" \
V=99 "$@" >"$LOG_DIR/$logfile" 2>&1 || \
die "make $target failed, please check $logfile"
}
[ -d "$STAGING_DIR_HOST_TMPL" ] || {
echo "Bootstrapping build environment..."
rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST" "$BUILD_DIR" "$BUILD_DIR_HOST" "$KERNEL_BUILD_DIR"
mkdir -p "$STAGING_DIR" "$STAGING_DIR_HOST" \
"$BUILD_DIR" "$BUILD_DIR_HOST" "$KERNEL_BUILD_DIR"
bootstrap_native_make tools/install
bootstrap_native_make toolchain/install
bootstrap_deptest_make tools/install
bootstrap_deptest_make target/linux/install
cp -al "$STAGING_DIR_HOST" "$STAGING_DIR_HOST_TMPL"
rm -rf "$STAGING_DIR" "$STAGING_DIR_HOST" "$BUILD_DIR" "$BUILD_DIR_HOST"
echo "Build environment OK."
}
if [ -z "$packages" ]; then
# iterate over all packages
for pkg in `cat tmp/.packagedeps | grep CONFIG_PACKAGE | grep -v curdir | sed -e 's,.*[/=]\s*,,' | sort -u`; do
test_package "$pkg"
done
else
# only check the specified packages
for pkg in $packages; do
test_package "$pkg"
done
fi

16
scripts/diffconfig.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
grep \^CONFIG_TARGET_ .config | head -n3 > tmp/.diffconfig.head
grep \^CONFIG_TARGET_DEVICE_ .config >> tmp/.diffconfig.head
grep '^CONFIG_ALL=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_ALL_KMODS=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_ALL_NONSHARED=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_DEVEL=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_TOOLCHAINOPTS=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_BUSYBOX_CUSTOM=y' .config >> tmp/.diffconfig.head
grep '^CONFIG_TARGET_PER_DEVICE_ROOTFS=y' .config >> tmp/.diffconfig.head
./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage1 Config.in >/dev/null
./scripts/kconfig.pl '>+' tmp/.diffconfig.stage1 .config >> tmp/.diffconfig.head
./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage2 Config.in >/dev/null
./scripts/kconfig.pl '>' tmp/.diffconfig.stage2 .config >> tmp/.diffconfig.head
cat tmp/.diffconfig.head
rm -f tmp/.diffconfig tmp/.diffconfig.head

237
scripts/dl_cleanup.py Executable file
View File

@@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""
# OpenWrt download directory cleanup utility.
# Delete all but the very last version of the program tarballs.
#
# Copyright (C) 2010-2015 Michael Buesch <m@bues.ch>
# Copyright (C) 2013-2015 OpenWrt.org
"""
from __future__ import print_function
import sys
import os
import re
import getopt
# Commandline options
opt_dryrun = False
def parseVer_1234(match, filepath):
progname = match.group(1)
progversion = (int(match.group(2)) << 64) |\
(int(match.group(3)) << 48) |\
(int(match.group(4)) << 32) |\
(int(match.group(5)) << 16)
return (progname, progversion)
def parseVer_123(match, filepath):
progname = match.group(1)
try:
patchlevel = match.group(5)
except IndexError as e:
patchlevel = None
if patchlevel:
patchlevel = ord(patchlevel[0])
else:
patchlevel = 0
progversion = (int(match.group(2)) << 64) |\
(int(match.group(3)) << 48) |\
(int(match.group(4)) << 32) |\
patchlevel
return (progname, progversion)
def parseVer_12(match, filepath):
progname = match.group(1)
try:
patchlevel = match.group(4)
except IndexError as e:
patchlevel = None
if patchlevel:
patchlevel = ord(patchlevel[0])
else:
patchlevel = 0
progversion = (int(match.group(2)) << 64) |\
(int(match.group(3)) << 48) |\
patchlevel
return (progname, progversion)
def parseVer_r(match, filepath):
progname = match.group(1)
progversion = (int(match.group(2)) << 64)
return (progname, progversion)
def parseVer_ymd(match, filepath):
progname = match.group(1)
progversion = (int(match.group(2)) << 64) |\
(int(match.group(3)) << 48) |\
(int(match.group(4)) << 32)
return (progname, progversion)
def parseVer_GIT(match, filepath):
progname = match.group(1)
st = os.stat(filepath)
progversion = int(st.st_mtime) << 64
return (progname, progversion)
extensions = (
".tar.gz",
".tar.bz2",
".tar.xz",
".orig.tar.gz",
".orig.tar.bz2",
".orig.tar.xz",
".zip",
".tgz",
".tbz",
".txz",
)
versionRegex = (
(re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)\.(\d+)"), parseVer_1234), # xxx-1.2.3.4
(re.compile(r"(.+)[-_](\d\d\d\d)-?(\d\d)-?(\d\d)"), parseVer_ymd), # xxx-YYYY-MM-DD
(re.compile(r"(.+)[-_]([0-9a-fA-F]{40,40})"), parseVer_GIT), # xxx-GIT_SHASUM
(re.compile(r"(.+)[-_](\d+)\.(\d+)\.(\d+)(\w?)"), parseVer_123), # xxx-1.2.3a
(re.compile(r"(.+)[-_](\d+)_(\d+)_(\d+)"), parseVer_123), # xxx-1_2_3
(re.compile(r"(.+)[-_](\d+)\.(\d+)(\w?)"), parseVer_12), # xxx-1.2a
(re.compile(r"(.+)[-_]r?(\d+)"), parseVer_r), # xxx-r1111
)
blacklist = [
("linux", re.compile(r"linux-\d.*")),
("gcc", re.compile(r"gcc-.*")),
("wl_apsta", re.compile(r"wl_apsta.*")),
(".fw", re.compile(r".*\.fw")),
(".arm", re.compile(r".*\.arm")),
(".bin", re.compile(r".*\.bin")),
("rt-firmware", re.compile(r"RT[\d\w]+_Firmware.*")),
]
class EntryParseError(Exception): pass
class Entry:
def __init__(self, directory, filename):
self.directory = directory
self.filename = filename
self.progname = ""
self.fileext = ""
for ext in extensions:
if filename.endswith(ext):
filename = filename[0:0-len(ext)]
self.fileext = ext
break
else:
print(self.filename, "has an unknown file-extension")
raise EntryParseError("ext")
for (regex, parseVersion) in versionRegex:
match = regex.match(filename)
if match:
(self.progname, self.version) = parseVersion(
match, directory + "/" + filename + self.fileext)
break
else:
print(self.filename, "has an unknown version pattern")
raise EntryParseError("ver")
def getPath(self):
return (self.directory + "/" + self.filename).replace("//", "/")
def deleteFile(self):
path = self.getPath()
print("Deleting", path)
if not opt_dryrun:
os.unlink(path)
def __ge__(self, y):
return self.version >= y.version
def usage():
print("OpenWrt download directory cleanup utility")
print("Usage: " + sys.argv[0] + " [OPTIONS] <path/to/dl>")
print("")
print(" -d|--dry-run Do a dry-run. Don't delete any files")
print(" -B|--show-blacklist Show the blacklist and exit")
print(" -w|--whitelist ITEM Remove ITEM from blacklist")
def main(argv):
global opt_dryrun
try:
(opts, args) = getopt.getopt(argv[1:],
"hdBw:",
[ "help", "dry-run", "show-blacklist", "whitelist=", ])
if len(args) != 1:
usage()
return 1
except getopt.GetoptError as e:
usage()
return 1
directory = args[0]
for (o, v) in opts:
if o in ("-h", "--help"):
usage()
return 0
if o in ("-d", "--dry-run"):
opt_dryrun = True
if o in ("-w", "--whitelist"):
for i in range(0, len(blacklist)):
(name, regex) = blacklist[i]
if name == v:
del blacklist[i]
break
else:
print("Whitelist error: Item", v,\
"is not in blacklist")
return 1
if o in ("-B", "--show-blacklist"):
for (name, regex) in blacklist:
sep = "\t\t"
if len(name) >= 8:
sep = "\t"
print("%s%s(%s)" % (name, sep, regex.pattern))
return 0
# Create a directory listing and parse the file names.
entries = []
for filename in os.listdir(directory):
if filename == "." or filename == "..":
continue
for (name, regex) in blacklist:
if regex.match(filename):
if opt_dryrun:
print(filename, "is blacklisted")
break
else:
try:
entries.append(Entry(directory, filename))
except EntryParseError as e:
pass
# Create a map of programs
progmap = {}
for entry in entries:
if entry.progname in progmap.keys():
progmap[entry.progname].append(entry)
else:
progmap[entry.progname] = [entry,]
# Traverse the program map and delete everything but the last version
for prog in progmap:
lastVersion = None
versions = progmap[prog]
for version in versions:
if lastVersion is None or version >= lastVersion:
lastVersion = version
if lastVersion:
for version in versions:
if version is not lastVersion:
version.deleteFile()
if opt_dryrun:
print("Keeping", lastVersion.getPath())
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))

427
scripts/dl_github_archive.py Executable file
View File

@@ -0,0 +1,427 @@
#!/usr/bin/env python
#
# Copyright (c) 2018 Yousong Zhou <yszhou4tech@gmail.com>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
import argparse
import calendar
import datetime
import errno
import fcntl
import hashlib
import json
import os
import os.path
import re
import shutil
import ssl
import subprocess
import sys
import time
import urllib2
TMPDIR = os.environ.get('TMP_DIR') or '/tmp'
TMPDIR_DL = os.path.join(TMPDIR, 'dl')
class PathException(Exception): pass
class DownloadGitHubError(Exception): pass
class Path(object):
"""Context class for preparing and cleaning up directories.
If ```preclean` is ``False``, ``path`` will NOT be removed on context enter
If ``path`` ``isdir``, then it will be created on context enter.
If ``keep`` is True, then ``path`` will NOT be removed on context exit
"""
def __init__(self, path, isdir=True, preclean=False, keep=False):
self.path = path
self.isdir = isdir
self.preclean = preclean
self.keep = keep
def __enter__(self):
if self.preclean:
self.rm_all(self.path)
if self.isdir:
self.mkdir_all(self.path)
return self
def __exit__(self, exc_type, exc_value, traceback):
if not self.keep:
self.rm_all(self.path)
@staticmethod
def mkdir_all(path):
"""Same as mkdir -p."""
names = os.path.split(path)
p = ''
for name in names:
p = os.path.join(p, name)
Path._mkdir(p)
@staticmethod
def _rmdir_dir(dir_):
names = Path._listdir(dir_)
for name in names:
p = os.path.join(dir_, name)
Path.rm_all(p)
Path._rmdir(dir_)
@staticmethod
def _mkdir(path):
Path._os_func(os.mkdir, path, errno.EEXIST)
@staticmethod
def _rmdir(path):
Path._os_func(os.rmdir, path, errno.ENOENT)
@staticmethod
def _remove(path):
Path._os_func(os.remove, path, errno.ENOENT)
@staticmethod
def _listdir(path):
return Path._os_func(os.listdir, path, errno.ENOENT, default=[])
@staticmethod
def _os_func(func, path, errno, default=None):
"""Call func(path) in an idempotent way.
On exception ``ex``, if the type is OSError and ``ex.errno == errno``,
return ``default``, otherwise, re-raise
"""
try:
return func(path)
except OSError as e:
if e.errno == errno:
return default
else:
raise
@staticmethod
def rm_all(path):
"""Same as rm -r."""
if os.path.islink(path):
Path._remove(path)
elif os.path.isdir(path):
Path._rmdir_dir(path)
else:
Path._remove(path)
@staticmethod
def untar(path, into=None):
"""Extract tarball at ``path`` into subdir ``into``.
return subdir name if and only if there exists one, otherwise raise PathException
"""
args = ('tar', '-C', into, '-xzf', path, '--no-same-permissions')
subprocess.check_call(args, preexec_fn=lambda: os.umask(0o22))
dirs = os.listdir(into)
if len(dirs) == 1:
return dirs[0]
else:
raise PathException('untar %s: expecting a single subdir, got %s' % (path, dirs))
@staticmethod
def tar(path, subdir, into=None, ts=None):
"""Pack ``path`` into tarball ``into``."""
# --sort=name requires a recent build of GNU tar
args = ['tar', '--numeric-owner', '--owner=0', '--group=0', '--sort=name']
args += ['-C', path, '-cf', into, subdir]
envs = os.environ.copy()
if ts is not None:
args.append('--mtime=@%d' % ts)
if into.endswith('.xz'):
envs['XZ_OPT'] = '-7e'
args.append('-J')
elif into.endswith('.bz2'):
args.append('-j')
elif into.endswith('.gz'):
args.append('-z')
envs['GZIP'] = '-n'
else:
raise PathException('unknown compression type %s' % into)
subprocess.check_call(args, env=envs)
class GitHubCommitTsCache(object):
__cachef = 'github.commit.ts.cache'
__cachen = 2048
def __init__(self):
Path.mkdir_all(TMPDIR_DL)
self.cachef = os.path.join(TMPDIR_DL, self.__cachef)
self.cache = {}
def get(self, k):
"""Get timestamp with key ``k``."""
fileno = os.open(self.cachef, os.O_RDONLY | os.O_CREAT)
with os.fdopen(fileno) as fin:
try:
fcntl.lockf(fileno, fcntl.LOCK_SH)
self._cache_init(fin)
if k in self.cache:
ts = self.cache[k][0]
return ts
finally:
fcntl.lockf(fileno, fcntl.LOCK_UN)
return None
def set(self, k, v):
"""Update timestamp with ``k``."""
fileno = os.open(self.cachef, os.O_RDWR | os.O_CREAT)
with os.fdopen(fileno, 'w+') as f:
try:
fcntl.lockf(fileno, fcntl.LOCK_EX)
self._cache_init(f)
self.cache[k] = (v, int(time.time()))
self._cache_flush(f)
finally:
fcntl.lockf(fileno, fcntl.LOCK_UN)
def _cache_init(self, fin):
for line in fin:
k, ts, updated = line.split()
ts = int(ts)
updated = int(updated)
self.cache[k] = (ts, updated)
def _cache_flush(self, fout):
cache = sorted(self.cache.iteritems(), cmp=lambda a, b: b[1][1] - a[1][1])
cache = cache[:self.__cachen]
self.cache = {}
os.ftruncate(fout.fileno(), 0)
fout.seek(0, os.SEEK_SET)
for k, ent in cache:
ts = ent[0]
updated = ent[1]
line = '{0} {1} {2}\n'.format(k, ts, updated)
fout.write(line)
class DownloadGitHubTarball(object):
"""Download and repack archive tarabll from GitHub.
Compared with the method of packing after cloning the whole repo, this
method is more friendly to users with fragile internet connection.
However, there are limitations with this method
- GitHub imposes a 60 reqs/hour limit for unauthenticated API access.
This affects fetching commit date for reproducible tarballs. Download
through the archive link is not affected.
- GitHub archives do not contain source codes for submodules.
- GitHub archives seem to respect .gitattributes and ignore pathes with
export-ignore attributes.
For the first two issues, the method will fail loudly to allow fallback to
clone-then-pack method.
As for the 3rd issue, to make sure that this method only produces identical
tarballs as the fallback method, we require the expected hash value to be
supplied. That means the first tarball will need to be prepared by the
clone-then-pack method
"""
__repo_url_regex = re.compile(r'^(?:https|git)://github.com/(?P<owner>[^/]+)/(?P<repo>[^/]+)')
def __init__(self, args):
self.dl_dir = args.dl_dir
self.version = args.version
self.subdir = args.subdir
self.source = args.source
self.url = args.url
self._init_owner_repo()
self.xhash = args.hash
self._init_hasher()
self.commit_ts = None # lazy load commit timestamp
self.commit_ts_cache = GitHubCommitTsCache()
self.name = 'github-tarball'
def download(self):
"""Download and repack GitHub archive tarball."""
self._init_commit_ts()
with Path(TMPDIR_DL, keep=True) as dir_dl:
# fetch tarball from GitHub
tarball_path = os.path.join(dir_dl.path, self.subdir + '.tar.gz.dl')
with Path(tarball_path, isdir=False):
self._fetch(tarball_path)
# unpack
d = os.path.join(dir_dl.path, self.subdir + '.untar')
with Path(d, preclean=True) as dir_untar:
tarball_prefix = Path.untar(tarball_path, into=dir_untar.path)
dir0 = os.path.join(dir_untar.path, tarball_prefix)
dir1 = os.path.join(dir_untar.path, self.subdir)
# submodules check
if self._has_submodule(dir0):
raise self._error('Fetching submodules is not yet supported')
# rename subdir
os.rename(dir0, dir1)
# repack
into=os.path.join(TMPDIR_DL, self.source)
Path.tar(dir_untar.path, self.subdir, into=into, ts=self.commit_ts)
try:
self._hash_check(into)
except Exception:
Path.rm_all(into)
raise
# move to target location
file1 = os.path.join(self.dl_dir, self.source)
if into != file1:
shutil.move(into, file1)
def _has_submodule(self, dir_):
m = os.path.join(dir_, '.gitmodules')
try:
st = os.stat(m)
return st.st_size > 0
except OSError as e:
return e.errno != errno.ENOENT
def _init_owner_repo(self):
m = self.__repo_url_regex.search(self.url)
if m is None:
raise self._error('Invalid github url: {}'.format(self.url))
owner = m.group('owner')
repo = m.group('repo')
if repo.endswith('.git'):
repo = repo[:-4]
self.owner = owner
self.repo = repo
def _init_hasher(self):
xhash = self.xhash
if len(xhash) == 64:
self.hasher = hashlib.sha256()
elif len(xhash) == 32:
self.hasher = hashlib.md5()
else:
raise self._error('Requires sha256sum for verification')
self.xhash = xhash
def _hash_check(self, f):
with open(f, 'rb') as fin:
while True:
d = fin.read(4096)
if not d:
break
self.hasher.update(d)
xhash = self.hasher.hexdigest()
if xhash != self.xhash:
raise self._error('Wrong hash (probably caused by .gitattributes), expecting {}, got {}'.format(self.xhash, xhash))
def _init_commit_ts(self):
if self.commit_ts is not None:
return
# GitHub provides 2 APIs[1,2] for fetching commit data. API[1] is more
# terse while API[2] provides more verbose info such as commit diff
# etc. That's the main reason why API[1] is preferred: the response
# size is predictable.
#
# However, API[1] only accepts complete commit sha1sum as the parameter
# while API[2] is more liberal accepting also partial commit id and
# tags, etc.
#
# [1] Get a single commit, Repositories, https://developer.github.com/v3/repos/commits/#get-a-single-commit
# [2] Git Commits, Git Data, https://developer.github.com/v3/git/commits/#get-a-commit
apis = [
{
'url': self._make_repo_url_path('git', 'commits', self.version),
'attr_path': ('committer', 'date'),
}, {
'url': self._make_repo_url_path('commits', self.version),
'attr_path': ('commit', 'committer', 'date'),
},
]
version_is_sha1sum = len(self.version) == 40
if not version_is_sha1sum:
apis.insert(0, apis.pop())
for api in apis:
url = api['url']
attr_path = api['attr_path']
try:
ct = self.commit_ts_cache.get(url)
if ct is not None:
self.commit_ts = ct
return
ct = self._init_commit_ts_remote_get(url, attr_path)
self.commit_ts = ct
self.commit_ts_cache.set(url, ct)
return
except Exception:
pass
raise self._error('Cannot fetch commit ts: {}'.format(url))
def _init_commit_ts_remote_get(self, url, attrpath):
resp = self._make_request(url)
data = resp.read()
date = json.loads(data)
for attr in attrpath:
date = date[attr]
date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%SZ')
date = date.timetuple()
ct = calendar.timegm(date)
return ct
def _fetch(self, path):
"""Fetch tarball of the specified version ref."""
ref = self.version
url = self._make_repo_url_path('tarball', ref)
resp = self._make_request(url)
with open(path, 'wb') as fout:
while True:
d = resp.read(4096)
if not d:
break
fout.write(d)
def _make_repo_url_path(self, *args):
url = '/repos/{0}/{1}'.format(self.owner, self.repo)
if args:
url += '/' + '/'.join(args)
return url
def _make_request(self, path):
"""Request GitHub API endpoint on ``path``."""
url = 'https://api.github.com' + path
headers = {
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'OpenWrt',
}
req = urllib2.Request(url, headers=headers)
sslcontext = ssl._create_unverified_context()
fileobj = urllib2.urlopen(req, context=sslcontext)
return fileobj
def _error(self, msg):
return DownloadGitHubError('{}: {}'.format(self.source, msg))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--dl-dir', default=os.getcwd(), help='Download dir')
parser.add_argument('--url', help='Download URL')
parser.add_argument('--subdir', help='Source code subdir name')
parser.add_argument('--version', help='Source code version')
parser.add_argument('--source', help='Source tarball filename')
parser.add_argument('--hash', help='Source tarball\'s expected sha256sum')
args = parser.parse_args()
try:
method = DownloadGitHubTarball(args)
method.download()
except Exception as ex:
sys.stderr.write('{}: Download from {} failed\n'.format(args.source, args.url))
sys.stderr.write('{}\n'.format(ex))
sys.exit(1)
if __name__ == '__main__':
main()

295
scripts/download.pl Executable file
View File

@@ -0,0 +1,295 @@
#!/usr/bin/env perl
#
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2016 LEDE project
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
use strict;
use warnings;
use File::Basename;
use File::Copy;
use Text::ParseWords;
@ARGV > 2 or die "Syntax: $0 <target dir> <filename> <hash> <url filename> [<mirror> ...]\n";
my $url_filename;
my $target = glob(shift @ARGV);
my $filename = shift @ARGV;
my $file_hash = shift @ARGV;
$url_filename = shift @ARGV unless $ARGV[0] =~ /:\/\//;
my $scriptdir = dirname($0);
my @mirrors;
my $ok;
$url_filename or $url_filename = $filename;
sub localmirrors {
my @mlist;
open LM, "$scriptdir/localmirrors" and do {
while (<LM>) {
chomp $_;
push @mlist, $_ if $_;
}
close LM;
};
open CONFIG, "<".$ENV{'TOPDIR'}."/.config" and do {
while (<CONFIG>) {
/^CONFIG_LOCALMIRROR="(.+)"/ and do {
chomp;
my @local_mirrors = split(/;/, $1);
push @mlist, @local_mirrors;
};
}
close CONFIG;
};
my $mirror = $ENV{'DOWNLOAD_MIRROR'};
$mirror and push @mlist, split(/;/, $mirror);
return @mlist;
}
sub which($) {
my $prog = shift;
my $res = `which $prog`;
$res or return undef;
$res =~ /^no / and return undef;
$res =~ /not found/ and return undef;
return $res;
}
sub hash_cmd() {
my $len = length($file_hash);
my $cmd;
$len == 64 and return "mkhash sha256";
$len == 32 and return "mkhash md5";
return undef;
}
sub download_cmd($) {
my $url = shift;
my $have_curl = 0;
if (open CURL, '-|', 'curl', '--version') {
if (defined(my $line = readline CURL)) {
$have_curl = 1 if $line =~ /^curl /;
}
close CURL;
}
return $have_curl
? (qw(curl -f --connect-timeout 20 --retry 5 --location --insecure), shellwords($ENV{CURL_OPTIONS} || ''), $url)
: (qw(wget --tries=5 --timeout=20 --no-check-certificate --output-document=-), shellwords($ENV{WGET_OPTIONS} || ''), $url)
;
}
my $hash_cmd = hash_cmd();
$hash_cmd or ($file_hash eq "skip") or die "Cannot find appropriate hash command, ensure the provided hash is either a MD5 or SHA256 checksum.\n";
sub download
{
my $mirror = shift;
my $download_filename = shift;
$mirror =~ s!/$!!;
if ($mirror =~ s!^file://!!) {
if (! -d "$mirror") {
print STDERR "Wrong local cache directory -$mirror-.\n";
cleanup();
return;
}
if (! -d "$target") {
system("mkdir", "-p", "$target/");
}
if (! open TMPDLS, "find $mirror -follow -name $filename 2>/dev/null |") {
print("Failed to search for $filename in $mirror\n");
return;
}
my $link;
while (defined(my $line = readline TMPDLS)) {
chomp ($link = $line);
if ($. > 1) {
print("$. or more instances of $filename in $mirror found . Only one instance allowed.\n");
return;
}
}
close TMPDLS;
if (! $link) {
print("No instances of $filename found in $mirror.\n");
return;
}
print("Copying $filename from $link\n");
copy($link, "$target/$filename.dl");
$hash_cmd and do {
if (system("cat '$target/$filename.dl' | $hash_cmd > '$target/$filename.hash'")) {
print("Failed to generate hash for $filename\n");
return;
}
};
} else {
my @cmd = download_cmd("$mirror/$download_filename");
print STDERR "+ ".join(" ",@cmd)."\n";
open(FETCH_FD, '-|', @cmd) or die "Cannot launch curl or wget.\n";
$hash_cmd and do {
open MD5SUM, "| $hash_cmd > '$target/$filename.hash'" or die "Cannot launch $hash_cmd.\n";
};
open OUTPUT, "> $target/$filename.dl" or die "Cannot create file $target/$filename.dl: $!\n";
my $buffer;
while (read FETCH_FD, $buffer, 1048576) {
$hash_cmd and print MD5SUM $buffer;
print OUTPUT $buffer;
}
$hash_cmd and close MD5SUM;
close FETCH_FD;
close OUTPUT;
if ($? >> 8) {
print STDERR "Download failed.\n";
cleanup();
return;
}
}
$hash_cmd and do {
my $sum = `cat "$target/$filename.hash"`;
$sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n";
$sum = $1;
if ($sum ne $file_hash) {
print STDERR "Hash of the downloaded file does not match (file: $sum, requested: $file_hash) - deleting download.\n";
cleanup();
return;
}
};
unlink "$target/$filename";
system("mv", "$target/$filename.dl", "$target/$filename");
cleanup();
}
sub cleanup
{
unlink "$target/$filename.dl";
unlink "$target/$filename.hash";
}
@mirrors = localmirrors();
foreach my $mirror (@ARGV) {
if ($mirror =~ /^\@SF\/(.+)$/) {
# give sourceforge a few more tries, because it redirects to different mirrors
for (1 .. 5) {
push @mirrors, "https://downloads.sourceforge.net/$1";
}
} elsif ($mirror =~ /^\@APACHE\/(.+)$/) {
push @mirrors, "https://mirror.netcologne.de/apache.org/$1";
push @mirrors, "https://mirror.aarnet.edu.au/pub/apache/$1";
push @mirrors, "https://mirror.csclub.uwaterloo.ca/apache/$1";
push @mirrors, "https://archive.apache.org/dist/$1";
push @mirrors, "http://mirror.cogentco.com/pub/apache/$1";
push @mirrors, "http://mirror.navercorp.com/apache/$1";
push @mirrors, "http://ftp.jaist.ac.jp/pub/apache/$1";
push @mirrors, "ftp://apache.cs.utah.edu/apache.org/$1";
push @mirrors, "ftp://apache.mirrors.ovh.net/ftp.apache.org/dist/$1";
} elsif ($mirror =~ /^\@GITHUB\/(.+)$/) {
# give github a few more tries (different mirrors)
for (1 .. 5) {
push @mirrors, "https://raw.githubusercontent.com/$1";
}
} elsif ($mirror =~ /^\@GNU\/(.+)$/) {
push @mirrors, "https://mirror.csclub.uwaterloo.ca/gnu/$1";
push @mirrors, "https://mirror.netcologne.de/gnu/$1";
push @mirrors, "http://ftp.kddilabs.jp/GNU/gnu/$1";
push @mirrors, "http://www.nic.funet.fi/pub/gnu/gnu/$1";
push @mirrors, "http://mirror.internode.on.net/pub/gnu/$1";
push @mirrors, "http://mirror.navercorp.com/gnu/$1";
push @mirrors, "ftp://mirrors.rit.edu/gnu/$1";
push @mirrors, "ftp://download.xs4all.nl/pub/gnu/";
} elsif ($mirror =~ /^\@SAVANNAH\/(.+)$/) {
push @mirrors, "https://mirror.netcologne.de/savannah/$1";
push @mirrors, "https://mirror.csclub.uwaterloo.ca/nongnu/$1";
push @mirrors, "http://ftp.acc.umu.se/mirror/gnu.org/savannah/$1";
push @mirrors, "http://nongnu.uib.no/$1";
push @mirrors, "http://ftp.igh.cnrs.fr/pub/nongnu/$1";
push @mirrors, "http://public.p-knowledge.co.jp/Savannah-nongnu-mirror/$1";
push @mirrors, "ftp://cdimage.debian.org/mirror/gnu.org/savannah/$1";
push @mirrors, "ftp://ftp.acc.umu.se/mirror/gnu.org/savannah/$1";
} elsif ($mirror =~ /^\@KERNEL\/(.+)$/) {
my @extra = ( $1 );
if ($filename =~ /linux-\d+\.\d+(?:\.\d+)?-rc/) {
push @extra, "$extra[0]/testing";
} elsif ($filename =~ /linux-(\d+\.\d+(?:\.\d+)?)/) {
push @extra, "$extra[0]/longterm/v$1";
}
foreach my $dir (@extra) {
push @mirrors, "https://cdn.kernel.org/pub/$dir";
push @mirrors, "https://mirror.rackspace.com/kernel.org/$dir";
push @mirrors, "http://download.xs4all.nl/ftp.kernel.org/pub/$dir";
push @mirrors, "http://mirrors.mit.edu/kernel/$dir";
push @mirrors, "http://ftp.nara.wide.ad.jp/pub/kernel.org/$dir";
push @mirrors, "http://www.ring.gr.jp/archives/linux/kernel.org/$dir";
push @mirrors, "ftp://ftp.riken.jp/Linux/kernel.org/$dir";
push @mirrors, "ftp://www.mirrorservice.org/sites/ftp.kernel.org/pub/$dir";
}
} elsif ($mirror =~ /^\@GNOME\/(.+)$/) {
push @mirrors, "https://mirror.csclub.uwaterloo.ca/gnome/sources/$1";
push @mirrors, "http://ftp.acc.umu.se/pub/GNOME/sources/$1";
push @mirrors, "http://ftp.kaist.ac.kr/gnome/sources/$1";
push @mirrors, "http://www.mirrorservice.org/sites/ftp.gnome.org/pub/GNOME/sources/$1";
push @mirrors, "http://mirror.internode.on.net/pub/gnome/sources/$1";
push @mirrors, "http://ftp.belnet.be/ftp.gnome.org/sources/$1";
push @mirrors, "ftp://ftp.cse.buffalo.edu/pub/Gnome/sources/$1";
push @mirrors, "ftp://ftp.nara.wide.ad.jp/pub/X11/GNOME/sources/$1";
}
else {
push @mirrors, $mirror;
}
}
#push @mirrors, 'https://mirror1.openwrt.org';
push @mirrors, 'https://sources.openwrt.org';
push @mirrors, 'https://mirror2.openwrt.org/sources';
if (-f "$target/$filename") {
$hash_cmd and do {
if (system("cat '$target/$filename' | $hash_cmd > '$target/$filename.hash'")) {
die "Failed to generate hash for $filename\n";
}
my $sum = `cat "$target/$filename.hash"`;
$sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n";
$sum = $1;
cleanup();
exit 0 if $sum eq $file_hash;
die "Hash of the local file $filename does not match (file: $sum, requested: $file_hash) - deleting download.\n";
unlink "$target/$filename";
};
}
while (!-f "$target/$filename") {
my $mirror = shift @mirrors;
$mirror or die "No more mirrors to try - giving up.\n";
download($mirror, $url_filename);
if (!-f "$target/$filename" && $url_filename ne $filename) {
download($mirror, $filename);
}
}
$SIG{INT} = \&cleanup;

91
scripts/dump-target-info.pl Executable file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Cwd;
my (%targets, %architectures);
$ENV{'TOPDIR'} = Cwd::getcwd();
sub parse_targetinfo {
my ($target_dir, $subtarget) = @_;
if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 SUBTARGET='$subtarget' |") {
my ($target_name, $target_arch, @target_features);
while (defined(my $line = readline M)) {
chomp $line;
if ($line =~ /^Target: (.+)$/) {
$target_name = $1;
}
elsif ($line =~ /^Target-Arch-Packages: (.+)$/) {
$target_arch = $1;
}
elsif ($line =~ /^Target-Features: (.+)$/) {
@target_features = split /\s+/, $1;
}
elsif ($line =~ /^@\@$/) {
if ($target_name && $target_arch &&
!grep { $_ eq 'broken' or $_ eq 'source-only' } @target_features) {
$targets{$target_name} = $target_arch;
$architectures{$target_arch} ||= [];
push @{$architectures{$target_arch}}, $target_name;
}
undef $target_name;
undef $target_arch;
@target_features = ();
}
}
close M;
}
}
sub get_targetinfo {
foreach my $target_makefile (glob "target/linux/*/Makefile") {
my ($target_dir) = $target_makefile =~ m!^(.+)/Makefile$!;
my @subtargets;
if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 val.FEATURES V=s 2>/dev/null |") {
if (defined(my $line = readline M)) {
chomp $line;
if (grep { $_ eq 'broken' or $_ eq 'source-only' } split /\s+/, $line) {
next;
}
}
}
if (open M, "make -C '$target_dir' --no-print-directory DUMP=1 TARGET_BUILD=1 val.SUBTARGETS V=s 2>/dev/null |") {
if (defined(my $line = readline M)) {
chomp $line;
@subtargets = split /\s+/, $line;
}
close M;
}
push @subtargets, 'generic' if @subtargets == 0;
foreach my $subtarget (@subtargets) {
parse_targetinfo($target_dir, $subtarget);
}
}
}
if (@ARGV == 1 && $ARGV[0] eq 'targets') {
get_targetinfo();
foreach my $target_name (sort keys %targets) {
printf "%s %s\n", $target_name, $targets{$target_name};
}
}
elsif (@ARGV == 1 && $ARGV[0] eq 'architectures') {
get_targetinfo();
foreach my $target_arch (sort keys %architectures) {
printf "%s %s\n", $target_arch, join ' ', @{$architectures{$target_arch}};
}
}
else {
print "Usage: $0 targets\n";
print "Usage: $0 architectures\n";
}

226
scripts/env Executable file
View File

@@ -0,0 +1,226 @@
#!/usr/bin/env bash
BASEDIR="$PWD"
ENVDIR="$PWD/env"
export GREP_OPTIONS=
usage() {
cat <<EOF
Usage: $0 [options] <command> [arguments]
Commands:
help This help text
list List environments
clear Delete all environment and revert to flat config/files
new <name> Create a new environment
switch <name> Switch to a different environment
delete <name> Delete an environment
rename <newname> Rename the current environment
diff Show differences between current state and environment
save [message] Save your changes to the environment, optionally using
the given commit message
revert Revert your changes since last save
Options:
EOF
exit ${1:-1}
}
error() {
echo "$0: $*"
exit 1
}
ask_bool() {
local DEFAULT="$1"; shift
local def defstr val
case "$DEFAULT" in
1) def=0; defstr="Y/n";;
0) def=1; defstr="y/N";;
*) def=; defstr="y/n";;
esac
while [ -z "$val" ]; do
local VAL
echo -n "$* ($defstr): "
read VAL
case "$VAL" in
y*|Y*) val=0;;
n*|N*) val=1;;
*) val="$def";;
esac
done
return "$val"
}
env_init() {
local CREATE="$1"
if [ -z "$CREATE" ]; then
[ -d "$ENVDIR" ] || exit 0
fi
[ -x "$(which git 2>/dev/null)" ] || error "Git is not installed"
mkdir -p "$ENVDIR" || error "Failed to create the environment directory"
cd "$ENVDIR" || error "Failed to switch to the environment directory"
[ -d .git ] || {
git init &&
touch .config &&
mkdir files &&
git add . &&
git commit -q -m "Initial import"
} || {
rm -rf .git
error "Failed to initialize the environment directory"
}
}
env_sync_data() {
[ \! -L "$BASEDIR/.config" -a -f "$BASEDIR/.config" ] && mv "$BASEDIR/.config" "$ENVDIR"
git add .
git add -u
}
env_sync() {
local STR="$1"
env_sync_data
git commit -m "${STR:-Update} at $(date)"
}
env_link_config() {
rm -f "$BASEDIR/.config"
ln -s env/.config "$BASEDIR/.config"
mkdir -p "$ENVDIR/files"
[ -L "$BASEDIR/files" ] || ln -s env/files "$BASEDIR/files"
}
env_do_reset() {
git reset --hard HEAD
git clean -d -f
}
env_list() {
env_init
git branch --color | grep -vE '^. master$'
}
env_diff() {
env_init
env_sync_data
git diff --cached --color=auto
env_link_config
}
env_save() {
env_init
env_sync "$@"
env_link_config
}
env_revert() {
env_init
env_do_reset
env_link_config
}
env_ask_sync() {
env_sync_data
LINES="$(env_diff | wc -l)" # implies env_init
[ "$LINES" -gt 0 ] && {
if ask_bool 1 "Do you want to save your changes"; then
env_sync
else
env_do_reset
fi
}
}
env_clear() {
env_init
[ -L "$BASEDIR/.config" ] && rm -f "$BASEDIR/.config"
[ -L "$BASEDIR/files" ] && rm -f "$BASEDIR/files"
[ -f "$ENVDIR/.config" ] || ( cd "$ENVDIR/files" && find | grep -vE '^\.$' > /dev/null )
env_sync_data
if ask_bool 1 "Do you want to keep your current config and files"; then
mkdir -p "$BASEDIR/files"
shopt -s dotglob
cp -a "$ENVDIR/files/"* "$BASEDIR/files" 2>/dev/null >/dev/null
shopt -u dotglob
cp "$ENVDIR/.config" "$BASEDIR/"
else
rm -rf "$BASEDIR/files" "$BASEDIR/.config"
fi
cd "$BASEDIR"
rm -rf "$ENVDIR"
}
env_delete() {
local name="${1##*/}"
env_init
[ -z "$name" ] && usage
branch="$(git branch | grep '^\* ' | awk '{print $2}')"
[ "$name" = "$branch" ] && error "cannot delete the currently selected environment"
git branch -D "$name"
}
env_switch() {
local name="${1##*/}"
[ -z "$name" ] && usage
env_init
env_ask_sync
git checkout "$name" || error "environment '$name' not found"
env_link_config
}
env_rename() {
local NAME="${1##*/}"
env_init
git branch -m "$NAME"
}
env_new() {
local NAME="$1"
local branch
local from="master"
[ -z "$NAME" ] && usage
env_init 1
branch="$(git branch | grep '^\* ' | awk '{print $2}')"
if [ -n "$branch" -a "$branch" != "master" ]; then
env_ask_sync
if ask_bool 0 "Do you want to clone the current environment?"; then
from="$branch"
fi
rm -f "$BASEDIR/.config" "$BASEDIR/files"
fi
git checkout -b "$1" "$from"
if [ -f "$BASEDIR/.config" -o -d "$BASEDIR/files" ]; then
if ask_bool 1 "Do you want to start your configuration repository with the current configuration?"; then
[ -d "$BASEDIR/files" -a \! -L "$BASEDIR/files" ] && {
mkdir -p "$ENVDIR/files"
shopt -s dotglob
mv "$BASEDIR/files/"* "$ENVDIR/files/" 2>/dev/null
shopt -u dotglob
rmdir "$BASEDIR/files"
}
env_sync
else
rm -rf "$BASEDIR/.config" "$BASEDIR/files"
fi
fi
env_link_config
}
COMMAND="$1"; shift
case "$COMMAND" in
help) usage 0;;
new) env_new "$@";;
list) env_list "$@";;
clear) env_clear "$@";;
switch) env_switch "$@";;
delete) env_delete "$@";;
rename) env_rename "$@";;
diff) env_diff "$@";;
save) env_save "$@";;
revert) env_revert "$@";;
*) usage;;
esac

583
scripts/ext-toolchain.sh Executable file
View File

@@ -0,0 +1,583 @@
#!/usr/bin/env bash
#
# Script for various external toolchain tasks, refer to
# the --help output for more information.
#
# Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CC=""
CXX=""
CPP=""
CFLAGS=""
TOOLCHAIN="."
LIBC_TYPE=""
# Library specs
LIB_SPECS="
c: ld-* lib{anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}
rt: librt-* librt
pthread: libpthread-* libpthread
stdcpp: libstdc++
thread_db: libthread-db
gcc: libgcc_s
ssp: libssp
gfortran: libgfortran
gomp: libgomp
"
# Binary specs
BIN_SPECS="
ldd: ldd
ldconfig: ldconfig
gdb: gdb
gdbserver: gdbserver
"
test_c() {
cat <<-EOT | "${CC:-false}" $CFLAGS -o /dev/null -x c - 2>/dev/null
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello, world!\n");
return 0;
}
EOT
}
test_cxx() {
cat <<-EOT | "${CXX:-false}" $CFLAGS -o /dev/null -x c++ - 2>/dev/null
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world!" << endl;
return 0;
}
EOT
}
test_softfloat() {
cat <<-EOT | "$CC" $CFLAGS -msoft-float -o /dev/null -x c - 2>/dev/null
int main(int argc, char **argv)
{
double a = 0.1;
double b = 0.2;
double c = (a + b) / (a * b);
return 1;
}
EOT
}
test_uclibc() {
local sysroot="$("$CC" $CFLAGS -print-sysroot 2>/dev/null)"
if [ -d "${sysroot:-$TOOLCHAIN}" ]; then
local lib
for lib in "${sysroot:-$TOOLCHAIN}"/{lib,usr/lib,usr/local/lib}/ld*-uClibc*.so*; do
if [ -f "$lib" ] && [ ! -h "$lib" ]; then
return 0
fi
done
fi
return 1
}
test_feature() {
local feature="$1"; shift
# find compilers, libc type
probe_cc
probe_cxx
probe_libc
# common toolchain feature tests
case "$feature" in
c) test_c; return $? ;;
c++) test_cxx; return $? ;;
soft*) test_softfloat; return $? ;;
esac
# assume eglibc/glibc supports all libc features
if [ "$LIBC_TYPE" != "uclibc" ]; then
return 0
fi
# uclibc feature tests
local inc
local sysroot="$("$CC" "$@" -muclibc -print-sysroot 2>/dev/null)"
for inc in "include" "usr/include" "usr/local/include"; do
local conf="${sysroot:-$TOOLCHAIN}/$inc/bits/uClibc_config.h"
if [ -f "$conf" ]; then
case "$feature" in
lfs) grep -q '__UCLIBC_HAS_LFS__ 1' "$conf"; return $?;;
ipv6) grep -q '__UCLIBC_HAS_IPV6__ 1' "$conf"; return $?;;
rpc) grep -q '__UCLIBC_HAS_RPC__ 1' "$conf"; return $?;;
locale) grep -q '__UCLIBC_HAS_LOCALE__ 1' "$conf"; return $?;;
wchar) grep -q '__UCLIBC_HAS_WCHAR__ 1' "$conf"; return $?;;
threads) grep -q '__UCLIBC_HAS_THREADS__ 1' "$conf"; return $?;;
esac
fi
done
return 1
}
find_libs() {
local spec="$(echo "$LIB_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
if [ -n "$spec" ] && probe_cpp; then
local libdir libdirs
for libdir in $(
"$CPP" $CFLAGS -v -x c /dev/null 2>&1 | \
sed -ne 's#:# #g; s#^LIBRARY_PATH=##p'
); do
if [ -d "$libdir" ]; then
libdirs="$libdirs $(cd "$libdir"; pwd)/"
fi
done
local pattern
for pattern in $(eval echo $spec); do
find $libdirs -name "$pattern.so*" | sort -u
done
return 0
fi
return 1
}
find_bins() {
local spec="$(echo "$BIN_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
if [ -n "$spec" ] && probe_cpp; then
local sysroot="$("$CPP" -print-sysroot)"
local bindir bindirs
for bindir in $(
echo "${sysroot:-$TOOLCHAIN}/bin";
echo "${sysroot:-$TOOLCHAIN}/usr/bin";
echo "${sysroot:-$TOOLCHAIN}/usr/local/bin";
"$CPP" $CFLAGS -v -x c /dev/null 2>&1 | \
sed -ne 's#:# #g; s#^COMPILER_PATH=##p'
); do
if [ -d "$bindir" ]; then
bindirs="$bindirs $(cd "$bindir"; pwd)/"
fi
done
local pattern
for pattern in $(eval echo $spec); do
find $bindirs -name "$pattern" | sort -u
done
return 0
fi
return 1
}
wrap_bin_cc() {
local out="$1"
local bin="$2"
echo '#!/bin/sh' > "$out"
echo 'for arg in "$@"; do' >> "$out"
echo ' case "$arg" in -l*|-L*|-shared|-static)' >> "$out"
echo -n ' exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+' >> "$out"
echo -n '-idirafter "$STAGING_DIR/usr/include" ' >> "$out"
echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
echo '-Wl,-rpath-link,"$STAGING_DIR/usr/lib"} "$@" ;;' >> "$out"
echo ' esac' >> "$out"
echo 'done' >> "$out"
echo -n 'exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+' >> "$out"
echo '-idirafter "$STAGING_DIR/usr/include"} "$@"' >> "$out"
chmod +x "$out"
}
wrap_bin_ld() {
local out="$1"
local bin="$2"
echo '#!/bin/sh' > "$out"
echo -n 'exec "'"$bin"'" ${STAGING_DIR:+' >> "$out"
echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
echo '-rpath-link "$STAGING_DIR/usr/lib"} "$@"' >> "$out"
chmod +x "$out"
}
wrap_bin_other() {
local out="$1"
local bin="$2"
echo '#!/bin/sh' > "$out"
echo 'exec "'"$bin"'" "$@"' >> "$out"
chmod +x "$out"
}
wrap_bins() {
if probe_cc; then
mkdir -p "$1" || return 1
local cmd
for cmd in "${CC%-*}-"*; do
if [ -x "$cmd" ]; then
local out="$1/${cmd##*/}"
local bin="$cmd"
if [ -x "$out" ] && ! grep -q STAGING_DIR "$out"; then
mv "$out" "$out.bin"
bin='$(dirname "$0")/'"${out##*/}"'.bin'
fi
case "${cmd##*/}" in
*-*cc|*-*cc-*|*-*++|*-*++-*|*-cpp)
wrap_bin_cc "$out" "$bin"
;;
*-ld)
wrap_bin_ld "$out" "$bin"
;;
*)
wrap_bin_other "$out" "$bin"
;;
esac
fi
done
return 0
fi
return 1
}
print_config() {
local mktarget="$1"
local mksubtarget
local target="$("$CC" $CFLAGS -dumpmachine)"
local cpuarch="${target%%-*}"
local prefix="${CC##*/}"; prefix="${prefix%-*}-"
local config="${0%/scripts/*}/.config"
# if no target specified, print choice list and exit
if [ -z "$mktarget" ]; then
# prepare metadata
if [ ! -f "${0%/scripts/*}/tmp/.targetinfo" ]; then
"${0%/*}/scripts/config/mconf" prepare-tmpinfo
fi
local mktargets=$(
sed -ne "
/^Target: / { h };
/^Target-Arch: $cpuarch\$/ { x; s#^Target: ##p }
" "${0%/scripts/*}/tmp/.targetinfo" | sort -u
)
for mktarget in $mktargets; do
case "$mktarget" in */*)
mktargets=$(echo "$mktargets" | sed -e "/^${mktarget%/*}\$/d")
esac
done
if [ -n "$mktargets" ]; then
echo "Available targets:" >&2
echo $mktargets >&2
else
echo -e "Could not find a suitable OpenWrt target for " >&2
echo -e "CPU architecture '$cpuarch' - you need to " >&2
echo -e "define one first!" >&2
fi
return 1
fi
# bail out if there is a .config already
if [ -f "${0%/scripts/*}/.config" ]; then
echo "There already is a .config file, refusing to overwrite!" >&2
return 1
fi
case "$mktarget" in */*)
mksubtarget="${mktarget#*/}"
mktarget="${mktarget%/*}"
;; esac
echo "CONFIG_TARGET_${mktarget}=y" > "$config"
if [ -n "$mksubtarget" ]; then
echo "CONFIG_TARGET_${mktarget}_${mksubtarget}=y" >> "$config"
fi
if test_feature "softfloat"; then
echo "CONFIG_SOFT_FLOAT=y" >> "$config"
else
echo "# CONFIG_SOFT_FLOAT is not set" >> "$config"
fi
if test_feature "ipv6"; then
echo "CONFIG_IPV6=y" >> "$config"
else
echo "# CONFIG_IPV6 is not set" >> "$config"
fi
if test_feature "locale"; then
echo "CONFIG_BUILD_NLS=y" >> "$config"
else
echo "# CONFIG_BUILD_NLS is not set" >> "$config"
fi
echo "CONFIG_DEVEL=y" >> "$config"
echo "CONFIG_EXTERNAL_TOOLCHAIN=y" >> "$config"
echo "CONFIG_TOOLCHAIN_ROOT=\"$TOOLCHAIN\"" >> "$config"
echo "CONFIG_TOOLCHAIN_PREFIX=\"$prefix\"" >> "$config"
echo "CONFIG_TARGET_NAME=\"$target\"" >> "$config"
if [ "$LIBC_TYPE" != glibc ]; then
echo "CONFIG_TOOLCHAIN_LIBC=\"$LIBC_TYPE\"" >> "$config"
fi
local lib
for lib in C RT PTHREAD GCC STDCPP SSP GFORTRAN GOMP; do
local file
local spec=""
local llib="$(echo "$lib" | sed -e 's#.*#\L&#')"
for file in $(find_libs "$lib"); do
spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
done
if [ -n "$spec" ]; then
echo "CONFIG_PACKAGE_lib${llib}=y" >> "$config"
echo "CONFIG_LIB${lib}_FILE_SPEC=\"$spec\"" >> "$config"
else
echo "# CONFIG_PACKAGE_lib${llib} is not set" >> "$config"
fi
done
local bin
for bin in LDD LDCONFIG; do
local file
local spec=""
local lbin="$(echo "$bin" | sed -e 's#.*#\L&#')"
for file in $(find_bins "$bin"); do
spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
done
if [ -n "$spec" ]; then
echo "CONFIG_PACKAGE_${lbin}=y" >> "$config"
echo "CONFIG_${bin}_FILE_SPEC=\"$spec\"" >> "$config"
else
echo "# CONFIG_PACKAGE_${lbin} is not set" >> "$config"
fi
done
# inflate
make -C "${0%/scripts/*}" defconfig
return 0
}
probe_cc() {
if [ -z "$CC" ]; then
local bin
for bin in "bin" "usr/bin" "usr/local/bin"; do
local cmd
for cmd in "$TOOLCHAIN/$bin/"*-*cc*; do
if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
CC="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
return 0
fi
done
done
return 1
fi
return 0
}
probe_cxx() {
if [ -z "$CXX" ]; then
local bin
for bin in "bin" "usr/bin" "usr/local/bin"; do
local cmd
for cmd in "$TOOLCHAIN/$bin/"*-*++*; do
if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
CXX="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
return 0
fi
done
done
return 1
fi
return 0
}
probe_cpp() {
if [ -z "$CPP" ]; then
local bin
for bin in "bin" "usr/bin" "usr/local/bin"; do
local cmd
for cmd in "$TOOLCHAIN/$bin/"*-cpp*; do
if [ -x "$cmd" ] && [ ! -h "$cmd" ]; then
CPP="$(cd "${cmd%/*}"; pwd)/${cmd##*/}"
return 0
fi
done
done
return 1
fi
return 0
}
probe_libc() {
if [ -z "$LIBC_TYPE" ]; then
if test_uclibc; then
LIBC_TYPE="uclibc"
else
LIBC_TYPE="glibc"
fi
fi
return 0
}
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
--toolchain)
[ -d "$1" ] || {
echo "Toolchain directory '$1' does not exist." >&2
exit 1
}
TOOLCHAIN="$(cd "$1"; pwd)"; shift
;;
--cflags)
CFLAGS="${CFLAGS:+$CFLAGS }$1"; shift
;;
--print-libc)
if probe_cc; then
probe_libc
echo "$LIBC_TYPE"
exit 0
fi
echo "No C compiler found in '$TOOLCHAIN'." >&2
exit 1
;;
--print-target)
if probe_cc; then
exec "$CC" $CFLAGS -dumpmachine
fi
echo "No C compiler found in '$TOOLCHAIN'." >&2
exit 1
;;
--print-bin)
if [ -z "$1" ]; then
echo "Available programs:" >&2
echo $(echo "$BIN_SPECS" | sed -ne 's#:.*$##p') >&2
exit 1
fi
find_bins "$1" || exec "$0" --toolchain "$TOOLCHAIN" --print-bin
exit 0
;;
--print-libs)
if [ -z "$1" ]; then
echo "Available libraries:" >&2
echo $(echo "$LIB_SPECS" | sed -ne 's#:.*$##p') >&2
exit 1
fi
find_libs "$1" || exec "$0" --toolchain "$TOOLCHAIN" --print-libs
exit 0
;;
--test)
test_feature "$1"
exit $?
;;
--wrap)
[ -n "$1" ] || exec "$0" --help
wrap_bins "$1"
exit $?
;;
--config)
if probe_cc; then
print_config "$1"
exit $?
fi
echo "No C compiler found in '$TOOLCHAIN'." >&2
exit 1
;;
-h|--help)
me="$(basename "$0")"
echo -e "\nUsage:\n" >&2
echo -e " $me --toolchain {directory} --print-libc" >&2
echo -e " Print the libc implementation and exit.\n" >&2
echo -e " $me --toolchain {directory} --print-target" >&2
echo -e " Print the GNU target name and exit.\n" >&2
echo -e " $me --toolchain {directory} --print-bin {program}" >&2
echo -e " Print executables belonging to given program," >&2
echo -e " omit program argument to get a list of names.\n" >&2
echo -e " $me --toolchain {directory} --print-libs {library}" >&2
echo -e " Print shared objects belonging to given library," >&2
echo -e " omit library argument to get a list of names.\n" >&2
echo -e " $me --toolchain {directory} --test {feature}" >&2
echo -e " Test given feature, exit code indicates success." >&2
echo -e " Possible features are 'c', 'c++', 'softfloat'," >&2
echo -e " 'lfs', 'rpc', 'ipv6', 'wchar', 'locale' and " >&2
echo -e " 'threads'.\n" >&2
echo -e " $me --toolchain {directory} --wrap {directory}" >&2
echo -e " Create wrapper scripts for C and C++ compiler, " >&2
echo -e " linker, assembler and other key executables in " >&2
echo -e " the directory given with --wrap.\n" >&2
echo -e " $me --toolchain {directory} --config {target}" >&2
echo -e " Analyze the given toolchain and print a suitable" >&2
echo -e " .config for the given target. Omit target " >&2
echo -e " argument to get a list of names.\n" >&2
echo -e " $me --help" >&2
echo -e " Display this help text and exit.\n\n" >&2
echo -e " Most commands also take a --cflags parameter which " >&2
echo -e " is used to specify C flags to be passed to the " >&2
echo -e " cross compiler when performing tests." >&2
echo -e " This paremter may be repeated multiple times." >&2
exit 1
;;
*)
echo "Unknown argument '$arg'" >&2
exec $0 --help
;;
esac
done
exec $0 --help

926
scripts/feeds Executable file
View File

@@ -0,0 +1,926 @@
#!/usr/bin/env perl
use Getopt::Std;
use FindBin;
use Cwd;
use lib "$FindBin::Bin";
use metadata;
use warnings;
use strict;
use Cwd 'abs_path';
chdir "$FindBin::Bin/..";
$ENV{TOPDIR} //= getcwd();
chdir $ENV{TOPDIR};
$ENV{GIT_CONFIG_PARAMETERS}="'core.autocrlf=false'";
$ENV{GREP_OPTIONS}="";
my $mk=`which gmake 2>/dev/null`; # select the right 'make' program
chomp($mk); # trim trailing newline
$mk or $mk = "make"; # default to 'make'
# check version of make
my @mkver = split /\s+/, `$mk -v`, 4;
my $valid_mk = 1;
$mkver[0] =~ /^GNU/ or $valid_mk = 0;
$mkver[1] =~ /^Make/ or $valid_mk = 0;
my ($mkv1, $mkv2) = split /\./, $mkver[2];
($mkv1 >= 4 || ($mkv1 == 3 && $mkv2 >= 81)) or $valid_mk = 0;
$valid_mk or die "Unsupported version of make found: $mk\n";
my @feeds;
my %build_packages;
my %installed;
my %installed_pkg;
my %installed_targets;
my %feed_cache;
my $feed_package = {};
my $feed_src = {};
my $feed_target = {};
my $feed_vpackage = {};
sub parse_file($$);
sub parse_file($$) {
my ($fname, $existing) = @_;
my $line = 0;
my $fh;
open $fh, $fname or return undef;
while (<$fh>) {
chomp;
s/#.+$//;
$line++;
next unless /\S/;
my ($type, $flags, $name, $urls) = m!^src-([\w\-]+)((?:\s+--\w+(?:=\S+)?)*)\s+(\w+)(?:\s+(\S.*))?$!;
unless ($type && $name) {
die "Syntax error in $fname, line $line\n";
}
if ($existing->{$name}++) {
die "Duplicate feed name '$name' in '$fname' line: $line\n";
}
my @src = defined($urls) ? split /\s+/, $urls : ();
push @src, '' if @src == 0;
my %flags;
if (defined $flags) {
while ($flags =~ m!\s+--(\w+)(?:=(\S+))?!g) {
$flags{$1} = defined($2) ? $2 : 1;
}
}
if ($type eq "include") {
parse_file($urls, $existing) or
die "Unable to open included file '$urls'";
next;
}
push @feeds, ["src-$type", $name, \@src, \%flags];
}
close $fh;
return 1;
}
sub parse_config() {
my %name;
parse_file("feeds.conf", \%name) or
parse_file("feeds.conf.default", \%name) or
die "Unable to open feeds configuration";
}
sub update_location($$)
{
my $name = shift;
my $url = shift;
my $old_url;
-d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1;
if( open LOC, "< ./feeds/$name.tmp/location" )
{
chomp($old_url = readline LOC);
close LOC;
}
if( !$old_url || $old_url ne $url )
{
if( open LOC, "> ./feeds/$name.tmp/location" )
{
print LOC $url, "\n";
close LOC;
}
return $old_url ? 1 : 0;
}
return 0;
}
sub update_index($)
{
my $name = shift;
-d "./feeds/$name.tmp" or mkdir "./feeds/$name.tmp" or return 1;
-d "./feeds/$name.tmp/info" or mkdir "./feeds/$name.tmp/info" or return 1;
system("$mk -s prepare-mk OPENWRT_BUILD= TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"packageinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"package\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
system("$mk -s -f include/scan.mk IS_TTY=1 SCAN_TARGET=\"targetinfo\" SCAN_DIR=\"feeds/$name\" SCAN_NAME=\"target\" SCAN_DEPTH=5 SCAN_EXTRA=\"\" SCAN_MAKEOPTS=\"TARGET_BUILD=1\" TMP_DIR=\"$ENV{TOPDIR}/feeds/$name.tmp\"");
system("ln -sf $name.tmp/.packageinfo ./feeds/$name.index");
system("ln -sf $name.tmp/.targetinfo ./feeds/$name.targetindex");
return 0;
}
my %update_method = (
'src-svn' => {
'init' => "svn checkout '%s' '%s'",
'update' => "svn update",
'controldir' => ".svn",
'revision' => "svn info | grep 'Revision' | cut -d ' ' -f 2 | tr -d '\n'"},
'src-cpy' => {
'init' => "cp -Rf '%s' '%s'",
'update' => "",
'revision' => "echo -n 'local'"},
'src-link' => {
'init' => "ln -s '%s' '%s'",
'update' => "",
'revision' => "echo -n 'local'"},
'src-dummy' => {
'init' => "true '%s' && mkdir '%s'",
'update' => "",
'revision' => "echo -n 'dummy'"},
'src-git' => {
'init' => "git clone --depth 1 '%s' '%s'",
'init_branch' => "git clone --depth 1 --branch '%s' '%s' '%s'",
'init_commit' => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -",
'update' => "git pull --ff",
'update_force' => "git pull --ff || (git reset --hard HEAD; git pull --ff; exit 1)",
'post_update' => "git submodule update --init --recursive",
'controldir' => ".git",
'revision' => "git rev-parse --short HEAD | tr -d '\n'"},
'src-git-full' => {
'init' => "git clone '%s' '%s'",
'init_branch' => "git clone --branch '%s' '%s' '%s'",
'init_commit' => "git clone '%s' '%s' && cd '%s' && git checkout -b '%s' '%s' && cd -",
'update' => "git pull --ff",
'update_force' => "git pull --ff || (git reset --hard HEAD; git pull --ff; exit 1)",
'post_update' => "git submodule update --init --recursive",
'controldir' => ".git",
'revision' => "git rev-parse --short HEAD | tr -d '\n'"},
'src-gitsvn' => {
'init' => "git svn clone -r HEAD '%s' '%s'",
'update' => "git svn rebase",
'controldir' => ".git",
'revision' => "git rev-parse --short HEAD | tr -d '\n'"},
'src-bzr' => {
'init' => "bzr checkout --lightweight '%s' '%s'",
'update' => "bzr update",
'controldir' => ".bzr"},
'src-hg' => {
'init' => "hg clone '%s' '%s'",
'update' => "hg pull --update",
'controldir' => ".hg"},
'src-darcs' => {
'init' => "darcs get '%s' '%s'",
'update' => "darcs pull -a",
'controldir' => "_darcs"},
);
# src-git: pull broken
# src-cpy: broken if `basename $src` != $name
sub update_feed_via($$$$$) {
my $type = shift;
my $name = shift;
my $src = shift;
my $relocate = shift;
my $force = shift;
my $m = $update_method{$type};
my $localpath = "./feeds/$name";
my $safepath = $localpath;
$safepath =~ s/'/'\\''/;
my ($base_branch, $branch) = split(/;/, $src, 2);
my ($base_commit, $commit) = split(/\^/, $src, 2);
if( $relocate || !$m->{'update'} || !-d "$localpath/$m->{'controldir'}" ) {
system("rm -rf '$safepath'");
if ($m->{'init_branch'} and $branch) {
system(sprintf($m->{'init_branch'}, $branch, $base_branch, $safepath)) == 0 or return 1;
} elsif ($m->{'init_commit'} and $commit) {
system(sprintf($m->{'init_commit'}, $base_commit, $safepath, $safepath, $commit, $commit)) == 0 or return 1;
} else {
system(sprintf($m->{'init'}, $src, $safepath)) == 0 or return 1;
}
} elsif ($m->{'init_commit'} and $commit) {
# in case git hash has been provided don't update the feed
} else {
my $update_cmd = $m->{'update'};
if ($force && exists $m->{'update_force'}) {
$update_cmd = $m->{'update_force'};
}
system("cd '$safepath'; $update_cmd") == 0 or return 1;
}
if ($m->{'post_update'}) {
my $cmd = $m->{'post_update'};
system("cd '$safepath'; $cmd") == 0 or return 1;
}
return 0;
}
sub get_targets($) {
my $file = shift;
my @target = parse_target_metadata($file);
my %target;
foreach my $target (@target) {
$target{$target->{id}} = $target;
}
return %target
}
sub get_feed($) {
my $feed = shift;
if (!defined($feed_cache{$feed})) {
my $file = "./feeds/$feed.index";
clear_packages();
-f $file or do {
print "Ignoring feed '$feed' - index missing\n";
return;
};
parse_package_metadata($file) or return;
my %target = get_targets("./feeds/$feed.targetindex");
$feed_cache{$feed} = [ { %package }, { %srcpackage }, { %target }, { %vpackage } ];
}
$feed_package = $feed_cache{$feed}->[0];
$feed_src = $feed_cache{$feed}->[1];
$feed_target = $feed_cache{$feed}->[2];
$feed_vpackage = $feed_cache{$feed}->[3];
}
sub get_installed() {
system("$mk -s prepare-tmpinfo OPENWRT_BUILD=");
clear_packages();
parse_package_metadata("./tmp/.packageinfo");
%installed_pkg = %vpackage;
%installed = %srcpackage;
%installed_targets = get_targets("./tmp/.targetinfo");
}
sub search_feed {
my $feed = shift;
my @substr = @_;
my $display;
return unless @substr > 0;
get_feed($feed);
foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) {
my $pkg = $feed_package->{$name};
my $substr;
my $pkgmatch = 1;
foreach my $substr (@substr) {
my $match;
foreach my $key (qw(name title description src)) {
$pkg->{$key} and $substr and $pkg->{$key} =~ m/$substr/i and $match = 1;
}
$match or undef $pkgmatch;
};
$pkgmatch and do {
$display or do {
print "Search results in feed '$feed':\n";
$display = 1;
};
printf "\%-25s\t\%s\n", $pkg->{name}, $pkg->{title};
};
}
foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) {
my $target = $feed_target->{$name};
my $targetmatch = 1;
foreach my $substr (@substr) {
my $match;
foreach my $key (qw(id name description)) {
$target->{$key} and $substr and $target->{$key} =~ m/$substr/i and $match = 1;
}
$match or undef $targetmatch;
};
$targetmatch and do {
$display or do {
print "Search results in feed '$feed':\n";
$display = 1;
};
printf "TARGET: \%-17s\t\%s\n", $target->{id}, $target->{name};
};
}
return 0;
}
sub search {
my %opts;
getopt('r:', \%opts);
foreach my $feed (@feeds) {
search_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]);
}
}
sub list_feed {
my $feed = shift;
get_feed($feed);
foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_package) {
my $pkg = $feed_package->{$name};
if($pkg->{name}) {
printf "\%-32s\t\%s\n", $pkg->{name}, $pkg->{title};
}
}
foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_target) {
my $target = $feed_target->{$name};
if($target->{name}) {
printf "TARGET: \%-24s\t\%s\n", $target->{id}, $target->{name};
}
}
return 0;
}
sub list {
my %opts;
getopts('r:d:nshf', \%opts);
if ($opts{h}) {
usage();
return 0;
}
if ($opts{n}) {
foreach my $feed (@feeds) {
printf "%s\n", $feed->[1];
}
return 0;
}
if ($opts{s}) {
foreach my $feed (@feeds) {
my $localpath = "./feeds/$feed->[1]";
my $m = $update_method{$feed->[0]};
my $revision;
if (!-d "$localpath" || !$m->{'revision'}) {
$revision = "X";
}
elsif( $m->{'controldir'} && -d "$localpath/$m->{'controldir'}" ) {
$revision = `cd '$localpath'; $m->{'revision'}`;
}
else {
$revision = "local";
}
if ($opts{d}) {
printf "%s%s%s%s%s%s%s\n", $feed->[1], $opts{d}, $feed->[0], $opts{d}, $revision, $opts{d}, join(", ", @{$feed->[2]});
}
elsif ($opts{f}) {
my $uri = join(", ", @{$feed->[2]});
if ($revision ne "local" && $revision ne "X") {
$uri =~ s/[;^].*//;
$uri .= "^" . $revision;
}
printf "%s %s %s\n", $feed->[0], $feed->[1], $uri;
}
else {
printf "\%-10s \%-8s \%-8s \%s\n", $feed->[1], $feed->[0], $revision, join(", ", @{$feed->[2]});
}
}
return 0;
}
foreach my $feed (@feeds) {
list_feed($feed->[1], @ARGV) if (!defined($opts{r}) or $opts{r} eq $feed->[1]);
}
return 0;
}
sub do_install_src($$) {
my $feed = shift;
my $src = shift;
my $path = $src->{makefile};
if ($path) {
$path =~ s/\/Makefile$//;
-d "./package/feeds" or mkdir "./package/feeds";
-d "./package/feeds/$feed->[1]" or mkdir "./package/feeds/$feed->[1]";
system("ln -sf ../../../$path ./package/feeds/$feed->[1]/");
} else {
warn "Package is not valid\n";
return 1;
}
return 0;
}
sub do_install_target($) {
my $target = shift;
my $path = $target->{makefile};
if ($path) {
$path =~ s/\/Makefile$//;
my $name = $path;
$name =~ s/.*\///;
my $dest = "./target/linux/$name";
-e $dest and do {
warn "Path $dest already exists";
return 1;
};
system("ln -sf ../../$path ./target/linux/");
} else {
warn "Target is not valid\n";
return 1;
}
return 0;
}
sub lookup_src($$) {
my $feed = shift;
my $src = shift;
foreach my $feed ($feed, @feeds) {
next unless $feed->[1];
next unless $feed_cache{$feed->[1]};
$feed_cache{$feed->[1]}->[1]->{$src} and return $feed;
}
return;
}
sub lookup_package($$) {
my $feed = shift;
my $package = shift;
foreach my $feed ($feed, @feeds) {
next unless $feed->[1];
next unless $feed_cache{$feed->[1]};
$feed_cache{$feed->[1]}->[3]->{$package} and return $feed;
}
return;
}
sub lookup_target($$) {
my $feed = shift;
my $target = shift;
foreach my $feed ($feed, @feeds) {
next unless $feed->[1];
next unless $feed_cache{$feed->[1]};
$feed_cache{$feed->[1]}->[2]->{$target} and return $feed;
}
return;
}
sub is_core_src($) {
my $src = shift;
foreach my $file ("tmp/info/.packageinfo-$src", glob("tmp/info/.packageinfo-*_$src")) {
next unless index($file, "tmp/info/.packageinfo-feeds_");
return 1 if -s $file;
}
return 0;
}
sub install_target {
my $feed = shift;
my $name = shift;
$installed_targets{$name} and return 0;
$feed = $feed_cache{$feed->[1]}->[2];
$feed or return 0;
my $target = $feed->{$name};
$target or return 0;
warn "Installing target '$name'\n";
return do_install_target($target);
}
sub install_src {
my $feed = shift;
my $name = shift;
my $force = shift;
my $ret = 0;
$feed = lookup_src($feed, $name);
unless ($feed) {
$installed{$name} and return 0;
$feed_src->{$name} or warn "WARNING: No feed for source package '$name' found\n";
return 0;
}
# switch to the metadata for the selected feed
get_feed($feed->[1]);
my $src = $feed_src->{$name} or return 1;
# enable force flag if feed src line was declared with --force
if (exists($feed->[3]{force})) {
$force = 1;
}
# If it's a core package and we don't want to override, just return
my $override = 0;
if (is_core_src($name)) {
return 0 unless $force;
$override = 1;
}
if ($installed{$name}) {
# newly installed packages set the source package to 1
return 0 if ($installed{$name} == 1);
return 0 unless ($override);
}
$installed{$name} = 1;
foreach my $pkg (@{$src->{packages}}) {
foreach my $vpkg (@{$pkg->{provides}}) {
$installed_pkg{$vpkg} = 1;
}
}
if ($override) {
warn "Overriding core package '$name' with version from $feed->[1]\n";
} else {
warn "Installing package '$name' from $feed->[1]\n";
}
do_install_src($feed, $src) == 0 or do {
warn "failed.\n";
return 1;
};
# install all dependencies referenced from the source package
foreach my $dep (
@{$src->{builddepends}},
@{$src->{'builddepends/host'}},
) {
next if $dep =~ /@/;
$dep =~ s/^.+://;
$dep =~ s/\/.+$//;
next unless $dep;
install_src($feed, $dep, 0) == 0 or $ret = 1;
}
foreach my $pkg (@{$src->{packages}}) {
foreach my $dep (@{$pkg->{depends}}) {
next if $dep =~ /@/;
$dep =~ s/^\+//;
$dep =~ s/^.+://;
next unless $dep;
install_package($feed, $dep, 0) == 0 or $ret = 1;
}
}
return $ret;
}
sub install_package {
my $feed = shift;
my $name = shift;
my $force = shift;
$feed = lookup_package($feed, $name);
unless ($feed) {
$installed_pkg{$name} and return 0;
$feed_vpackage->{$name} or warn "WARNING: No feed for package '$name' found\n";
return 0;
}
# switch to the metadata for the selected feed
get_feed($feed->[1]);
my $pkg = $feed_vpackage->{$name} or return 1;
return install_src($feed, $pkg->[0]{src}{name}, $force);
}
sub install_target_or_package {
my $feed = shift;
my $name = shift;
my $force = shift;
my $this_feed_target = lookup_target($feed, $name);
$this_feed_target and do {
return install_target($this_feed_target, $name);
};
my $this_feed_src = lookup_src($feed, $name);
$this_feed_src and do {
return install_src($this_feed_src, $name, $force);
};
return install_package($feed, $name, $force);
}
sub refresh_config {
my $default = shift;
# Don't create .config if it doesn't already exist so that making a
# config only occurs when the user intends it do (however we do
# want to refresh an existing config).
return if not (-e '.config');
# workaround for timestamp check
system("rm -f tmp/.packageinfo");
# refresh the config
if ($default) {
system("$mk oldconfig CONFDEFAULT=\"$default\" Config.in >/dev/null 2>/dev/null");
} else {
system("$mk defconfig Config.in >/dev/null 2>/dev/null");
}
}
sub install {
my $name;
my %opts;
my $feed;
my $ret = 0;
getopts('ap:d:fh', \%opts);
if ($opts{h}) {
usage();
return 0;
}
get_installed();
foreach my $f (@feeds) {
# fetch all feeds
get_feed($f->[1]);
# look up the preferred feed
$opts{p} and $f->[1] eq $opts{p} and $feed = $f;
}
if($opts{a}) {
foreach my $f (@feeds) {
if (!defined($opts{p}) or $opts{p} eq $f->[1]) {
printf "Installing all packages from feed %s.\n", $f->[1];
get_feed($f->[1]);
foreach my $name (sort { lc($a) cmp lc($b) } keys %$feed_src) {
install_src($feed, $name, exists($opts{f})) == 0 or $ret = 1;
get_feed($f->[1]);
}
}
}
} else {
while ($name = shift @ARGV) {
install_target_or_package($feed, $name, exists($opts{f})) == 0 or $ret = 1;
}
}
# workaround for timestamp check
# set the defaults
if ($opts{d} and $opts{d} =~ /^[ymn]$/) {
refresh_config($opts{d});
}
return $ret;
}
sub uninstall_target($) {
my $dir = shift;
my $name = $dir;
$name =~ s/.*\///g;
my $dest = readlink $dir;
return unless $dest =~ /..\/..\/feeds/;
warn "Uninstalling target '$name'\n";
unlink "$dir";
}
sub uninstall {
my %opts;
my $name;
my $uninstall;
getopts('ah', \%opts);
if ($opts{h}) {
usage();
return 0;
}
if ($opts{a}) {
system("rm -rvf ./package/feeds");
foreach my $dir (glob "target/linux/*") {
next unless -l $dir;
uninstall_target($dir);
}
$uninstall = 1;
} else {
if($#ARGV == -1) {
warn "WARNING: no package to uninstall\n";
return 0;
}
get_installed();
while ($name = shift @ARGV) {
my $target = "target/linux/$name";
-l "$target" and do {
uninstall_target($target);
$uninstall = 1;
next;
};
my $pkg = $installed{$name};
$pkg or do {
warn "WARNING: $name not installed\n";
next;
};
$pkg->{src} and $name = $pkg->{src}{name};
warn "Uninstalling package '$name'\n";
system("rm -f ./package/feeds/*/$name");
$uninstall = 1;
}
}
$uninstall and refresh_config();
return 0;
}
sub update_feed($$$$$)
{
my $type=shift;
my $name=shift;
my $src=shift;
my $perform_update=shift;
my $force_update=shift;
my $force_relocate=update_location( $name, "@$src" );
my $rv=0;
if( $force_relocate ) {
warn "Source of feed $name has changed, replacing copy\n";
}
$update_method{$type} or do {
warn "Unknown type '$type' in feed $name\n";
return 1;
};
$perform_update and do {
my $failed = 1;
foreach my $feedsrc (@$src) {
warn "Updating feed '$name' from '$feedsrc' ...\n";
if (update_feed_via($type, $name, $feedsrc, $force_relocate, $force_update) != 0) {
if ($force_update) {
$rv=1;
$failed=0;
warn "failed, ignore.\n";
next;
}
last;
}
$failed = 0;
}
$failed and do {
warn "failed.\n";
return 1;
};
};
warn "Create index file './feeds/$name.index' \n";
update_index($name) == 0 or do {
warn "failed.\n";
return 1;
};
return $rv;
}
sub update {
my %opts;
my $feed_name;
my $perform_update=1;
my $failed=0;
$ENV{SCAN_COOKIE} = $$;
$ENV{OPENWRT_VERBOSE} = 's';
getopts('ahif', \%opts);
if ($opts{h}) {
usage();
return 0;
}
if ($opts{i}) {
# don't update from (remote) repository
# only re-create index information
$perform_update=0;
}
-d "feeds" or do {
mkdir "feeds" or die "Unable to create the feeds directory";
};
if ( ($#ARGV == -1) or $opts{a}) {
foreach my $feed (@feeds) {
my ($type, $name, $src) = @$feed;
update_feed($type, $name, $src, $perform_update, $opts{f}) == 0 or $failed=1;
}
} else {
while ($feed_name = shift @ARGV) {
foreach my $feed (@feeds) {
my ($type, $name, $src) = @$feed;
if($feed_name ne $name) {
next;
}
update_feed($type, $name, $src, $perform_update, $opts{f}) == 0 or $failed=1;
}
}
}
refresh_config();
return $failed;
}
sub feed_config() {
foreach my $feed (@feeds) {
my $installed = (-f "feeds/$feed->[1].index");
printf "\tconfig FEED_%s\n", $feed->[1];
printf "\t\ttristate \"Enable feed %s\"\n", $feed->[1];
printf "\t\tdepends on PER_FEED_REPO\n";
printf "\t\tdefault y\n" if $installed;
printf "\t\thelp\n";
printf "\t\t Enable the \\\"%s\\\" feed in opkg distfeeds.conf.\n", $feed->[1];
printf "\t\t Say M to add the feed commented out.\n";
printf "\n";
}
return 0;
}
sub usage() {
print <<EOF;
Usage: $0 <command> [options]
Commands:
list [options]: List feeds, their content and revisions (if installed)
Options:
-n : List of feed names.
-s : List of feed names and their URL.
-r <feedname>: List packages of specified feed.
-d <delimiter>: Use specified delimiter to distinguish rows (default: spaces)
-f : List feeds in feeds.conf compatible format (when using -s).
install [options] <package>: Install a package
Options:
-a : Install all packages from all feeds or from the specified feed using the -p option.
-p <feedname>: Prefer this feed when installing packages.
-d <y|m|n>: Set default for newly installed packages.
-f : Install will be forced even if the package exists in core OpenWrt (override)
search [options] <substring>: Search for a package
Options:
-r <feedname>: Only search in this feed
uninstall -a|<package>: Uninstall a package
Options:
-a : Uninstalls all packages.
update -a|<feedname(s)>: Update packages and lists of feeds in feeds.conf .
Options:
-a : Update all feeds listed within feeds.conf. Otherwise the specified feeds will be updated.
-i : Recreate the index only. No feed update from repository is performed.
-f : Force updating feeds even if there are changed, uncommitted files.
clean: Remove downloaded/generated files.
EOF
exit(1);
}
my %commands = (
'list' => \&list,
'update' => \&update,
'install' => \&install,
'search' => \&search,
'uninstall' => \&uninstall,
'feed_config' => \&feed_config,
'clean' => sub {
system("rm -rf ./feeds ./package/feeds");
}
);
my $arg = shift @ARGV;
$arg or usage();
parse_config;
foreach my $cmd (keys %commands) {
$arg eq $cmd and do {
exit(&{$commands{$cmd}}());
};
}
usage();

135
scripts/fixup-makefile.pl Executable file
View File

@@ -0,0 +1,135 @@
#!/usr/bin/env perl
use strict;
my $error;
my %state;
sub usage() {
die <<EOF;
Usage: $0 <file> <command> [<arguments>]
Commands:
add-hash <variable> <value>
fix-hash <variable> <value>
rename-var <variable> <name>
EOF
}
sub set_var($) {
my $var = shift;
$state{var} = $var;
if ($var =~ /(.*):(.*)/) {
$state{template} = $1;
$state{var} = $2;
$state{related_var} = "URL";
} else {
$state{context} = 1;
$state{related_var} = "PKG_SOURCE_URL";
}
}
my %check_command = (
"add-hash" => sub {
set_var($ARGV[0]);
$state{value} = $ARGV[1];
length($ARGV[1]) == 64 or die "Invalid hash value\n";
},
"fix-hash" => sub {
set_var($ARGV[0]);
$state{value} = $ARGV[1];
$state{prev_value} = $ARGV[2];
length($ARGV[1]) == 64 or die "Invalid hash value\n";
},
"rename-var" => sub {
set_var($ARGV[0]);
$state{new_var} = $ARGV[1];
$state{new_var} =~ s/.*://g;
},
);
sub check_context($) {
my $line = shift;
return unless $state{template};
$state{next} and do {
$state{context} = 1;
undef $state{next};
return;
};
if (not $state{context}) {
$line =~ /^\s*define\s+$state{template}/ and $state{next} = 1;
} else {
$line =~ /^\s*endef/ and do {
$state{done} = 1;
undef $state{context};
}
}
}
my %commands = (
"add-hash" => sub {
my $line = shift;
check_context($line);
return $line unless $state{context};
# skip existing hash variable
return "" if $line =~ /^(\s*)$state{var}(\s*):?=(\s*)(.*)\n/;
# insert md5sum after related variable
return $line unless $line =~ /^(\s*)$state{related_var}(\s*):?=(\s*)(.*)\n/;
return "$line$1$state{var}$2:=$3$state{value}\n";
},
"fix-hash" => sub {
my $line = shift;
check_context($line);
return $line unless $state{context};
return $line unless $line =~ /^(\s*)$state{var}(\s*):?=(\s*)(.*)$state{prev_value}(.*)\n/;
$state{done} = 1;
$4 =~ /\$/ and do {
warn "$state{var} contains a reference to another variable, can't fix automatically\n";
return $line;
};
return "$1$state{var}$2:=$3$state{value}\n";
},
"rename-var" => sub {
my $line = shift;
check_context($line);
return $line unless $state{context};
return $line unless $line =~ /^(\s*)$state{var}(\s*:?=.*)\n/;
return "$1$state{new_var}$2\n";
},
);
my $file = shift @ARGV;
my $command = shift @ARGV;
($file and $command and $check_command{$command}) or usage;
&{$check_command{$command}}();
-f $file or die "File $file not found\n";
open IN, "<${file}" or die "Cannot open input file\n";
open OUT, ">${file}.new" or die "Cannot open output file\n";
my $cmd = $commands{$command};
while (my $line = <IN>) {
$line = &$cmd($line) unless $state{done};
print OUT $line;
last if $error;
}
close OUT;
close IN;
$error and do {
unlink "${file}.new";
exit 1;
};
rename "${file}.new", "$file";

View File

@@ -0,0 +1,342 @@
#!/usr/bin/env perl
#
# D-Link DSL-502T flash utility
#
# Copyright (c) 2007 Oliver Jowett <oliver@opencloud.com>
#
# Based on adam2flash.pl for the D-Link DSL-G6x4T, which is:
# Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
# based on fbox recovery util by Enrik Berkhan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# The default DSL-502T mtd map looks like this:
#
# mtd0 0x90091000,0x903f0000 # filesystem
# mtd1 0x90010090,0x90091000 # kernel
# mtd2 0x90000000,0x90010000 # bootloader - DO NOT MODIFY
# mtd3 0x903f0000,0x90400000 # config space - DO NOT MODIFY
# mtd4 0x90010000,0x903f0000 # firmware signature + kernel + filesystem, used to flash new firmware
#
# i.e. the flash layout is:
#
# 90000000-9000FFFF mtd2 bootloader
# 90010000-9001008F ---- firmware signature )
# 90010090-90090FFF mtd1 kernel ) mtd4 spans these three regions
# 90091000-903EFFFF mtd0 filesystem )
# 903F0000-903FFFFF mtd3 config space
#
# The ADAM2 bootloader uses the mtd1 settings to find the start of the image to boot.
# The image to load contains information about the loadable size of the image. If ADAM2 sees
# that the image appears to extend beyond the end of mtd1, it will refuse to load it. On
# the DSL-502T, this manifests as the USB light blinking rapidly on boot.
#
# The OpenWRT kernel does not follow quite the same layout:
# (a) it does not have a 0x90-byte firmware signature prefix
# (b) it is larger than the default mtd1 size
#
# (a) would be avoidable (build a custom image with a 0x90-byte prefix) but (b) is unavoidable.
# So we *have* to change mtd1. The simplest thing to do seems to make it span all of
# the flashable area, producing this layout:
#
# mtd0 0x90091000,0x903f0000 # filesystem
# mtd1 0x90010000,0x903f0000 # kernel (CHANGED)
# mtd2 0x90000000,0x90010000 # bootloader - DO NOT MODIFY
# mtd3 0x903f0000,0x90400000 # config space - DO NOT MODIFY
# mtd4 0x90010000,0x903f0000 # kernel + filesystem, used to flash new firmware
#
# *** NOTE NOTE NOTE NOTE ***
#
# /dev/mtd0 .. /dev/mtd4 when using OpenWRT do **NOT** correspond to the ADAM2 mtd0-4 settings!
# Instead, OpenWRT scans the MTD itself and determines its own boundaries which are arranged
# quite differently to ADAM2. It will look something like this, see dmsg on boot:
#
# (/dev/mtd0) 0x00000000-0x00010000 : "loader" # Bootloader, read-only
# (/dev/mtd1) 0x003f0000-0x00400000 : "config" # Config space
# (/dev/mtd2) 0x00010000-0x003f0000 : "linux" # Firmware area (kernel + root fs + JFFS area)
# (/dev/mtd3) 0x000d0d58-0x003f0000 : "rootfs" # Root FS, starts immediately after kernel
# (/dev/mtd4) 0x00280000-0x003f0000 : "rootfs_data" # If rootfs is squashfs, start of JFFS area.
#
# All of those boundaries are autodetected by examining the data in flash.
#
# *** NOTE NOTE NOTE NOTE ***
use IO::Socket::INET;
use Socket;
use strict;
use warnings;
sub usage() {
print STDERR "Usage: $0 <ip> [-setmtd1] [-noflash] [firmware.bin]\n\n";
print STDERR "Acquires the ADAM2 bootloader of a D-Link DSL-504T at <ip>\n";
print STDERR "Power off the device, start this script, then power it on.\n";
print STDERR "<ip> may be any spare address on the local subnet.\n\n";
print STDERR "If a firmware file is specified, MTD settings are verified and\n";
print STDERR "then the firmware is written to the router's flash.\n";
print STDERR "The firmware type (D-Link or OpenWRT) is automatically detected.\n\n";
print STDERR " -setmtd1 update mtd1 if it is not the appropriate value for this firmware\n";
print STDERR " -noflash does normal checks, updates mtd1 if requested, but does not actually write firmware\n\n";
exit 0;
}
my $ip = shift @ARGV;
$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
my $probe = IO::Socket::INET->new(Proto => 'udp',
Broadcast => 1,
LocalPort => 5035) or die "socket: $!";
my $setip = unpack("N", inet_aton($ip));
$setip > 0 or usage();
my @packets;
foreach my $ver ([18, 1], [22, 2]) {
push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
}
print STDERR "Looking for device: ";
my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
my $scanning;
my $box;
$SIG{"ALRM"} = sub {
return if --$scanning <= 0;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
};
$scanning = 15;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
while($scanning) {
my $reply;
alarm(1);
if (my $peer = $probe->recv($reply, 16)) {
next if (length($reply) < 16);
my ($port, $addr) = sockaddr_in($peer);
my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
$addr2 = pack("N", $addr2);
if ($code == 2) {
$scanning = 0;
printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
$box = inet_ntoa($addr);
}
}
}
$box or die " not found!\n";
alarm(0);
{
package ADAM2FTP;
use base qw(Net::FTP);
# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
sub _USER {
shift->command("USER",@_)->response()
}
sub _GETENV {
my $ftp = shift;
my ($ok, $name, $value);
$ftp->command("GETENV",@_);
while(length($ok = $ftp->response()) < 1) {
my $line = $ftp->getline();
unless (defined($value)) {
chomp($line);
($name, $value) = split(/\s+/, $line, 2);
}
}
$ftp->debug_print(0, "getenv: $value\n")
if $ftp->debug();
return $value;
}
sub getenv {
my $ftp = shift;
my $name = shift;
return $ftp->_GETENV($name);
}
sub _REBOOT {
shift->command("REBOOT")->response() == Net::FTP::CMD_OK
}
sub reboot {
my $ftp = shift;
$ftp->_REBOOT;
$ftp->close;
}
}
my $file;
my $arg;
my $noflash = 0;
my $setmtd1 = 0;
while ($arg = shift @ARGV) {
if ($arg eq "-noflash") { $noflash = 1; }
elsif ($arg eq "-setmtd1") { $setmtd1 = 1; }
else { $file = $arg; }
}
if (!$file) {
print STDERR "No firmware file specified, exiting.\n";
exit 0;
}
#
# Firmware checks
#
open FILE, "<$file" or die "can't open firmware file\n";
# D-Link firmware starts with "MTD4" little-endian, then has an image header at 0x90
# OpenWRT firmware just starts with an image header at 0x00
my $signature;
my $sbytes = read FILE, $signature, 4;
($sbytes == 4) or die "can't read firmware signature: $!";
my $expectedmtd4 = "0x90010000,0x903f0000";
my $fwtype;
my $expectedmtd1;
if ($signature eq "4DTM") {
seek FILE, 0x90, 0 or die "can't read firmware signature: $!";
$sbytes = read FILE, $signature, 4;
($sbytes == 4) or die "can't read firmware signature: $!";
if ($signature eq "\x42\xfa\xed\xfe") {
$fwtype = "D-Link (little-endian)";
$expectedmtd1 = "0x90010090,0x90091000";
} elsif ($signature eq "\xde\xad\xbe\x42") {
$fwtype = "D-Link (big-endian)";
$expectedmtd1 = "0x90010090,0x90091000";
}
} elsif ($signature eq "\x42\xfa\xed\xfe") {
$fwtype = "OpenWRT (little-endian)";
$expectedmtd1 = "0x90010000,0x903f0000";
} elsif ($signature eq "\xde\xad\xbe\x42") {
$fwtype = "OpenWRT (big-endian)";
$expectedmtd1 = "0x90010000,0x903f0000";
}
$fwtype or die "Unknown firmware signature (are you sure that's the right firmware?)";
print STDERR "Firmware type: $fwtype\n";
#
# Bootloader login
#
print STDERR "logging into ADAM2 bootloader.. ";
my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
$ftp->login("adam2", "adam2") or die "can't login\n";
print STDERR "ok.\n";
#
# Hardware checks
#
print STDERR "checking hardware.. ";
my $prd = $ftp->getenv("ProductID");
my $usb = $ftp->getenv("usb_prod");
print STDERR "$prd / $usb.\n";
($prd eq "AR7RD" || $prd eq "AR7DB") or die "doesn't look like a DSL-502T?";
($usb eq "DSL-502T") or die "doesn't look like a DSL-502T?";
#
# MTD checks and update
#
print STDERR "checking MTD settings.. ";
my $mtd4 = $ftp->getenv("mtd4");
($mtd4 eq $expectedmtd4) or die "MTD4 was not as expected (should be '$expectedmtd4', was '$mtd4'). Cowardly refusing to do anything about it!";
# check MTD1 setting and update if needed
my $mtd1 = $ftp->getenv("mtd1");
if ($mtd1 ne $expectedmtd1) {
die "MTD1 was not as expected (should be '$expectedmtd1', was '$mtd1'). Run with -setmtd1 to reset mtd1" unless ($setmtd1);
print STDERR "Setting mtd1.. ";
($ftp->command("SETENV","mtd1,$expectedmtd1")->response() == Net::FTP::CMD_OK) or die "can't set mtd1";
$file = shift @ARGV;
}
print STDERR "ok.\n";
#
# Firmware size check
#
my $fwsize = (stat(FILE))[7];
printf STDERR "Firmware size: 0x%08x\n", $fwsize;
my $flashsize;
$mtd4 =~ /^(0x\w+),(0x\w+)$/ and $flashsize = hex($2) - hex($1);
printf STDERR "Available flash space: 0x%08x\n", $flashsize;
die "firmware is too large" if ($flashsize < $fwsize);
#
# Flash it!
#
if ($noflash) {
print STDERR "Not flashing firmware as -noflash was specified.\n";
exit 0;
}
seek FILE, 0, 0, or die "can't seek in firmware: $!";
print STDERR "Preparing to flash.. ";
($ftp->command("MEDIA FLSH")->response() == Net::FTP::CMD_OK) or die "can't set MEDIA FLSH";
$ftp->binary() or die "can't set binary mode";
print STDERR "ok.\n";
print STDERR "Erasing flash and establishing data connection (this may take a while): ";
my $dc = $ftp->stor("fs mtd4");
$dc or die "can't open data connection: $!\n";
print STDERR "ok.\n";
print STDERR "Writing firmware: ";
while ($fwsize > 0) {
my $buffer;
my $len = ($fwsize > 1024 ? 1024 : $fwsize);
my $rbytes = read FILE, $buffer, $len;
($rbytes < 0) and die "read error on firmware file: $!";
($rbytes == $len) or die "short read on firmware file ($rbytes < $len)";
my $wbytes = $dc->write($buffer, $len, 600);
($wbytes < 0) and die "write error on FTP data connection: $!";
($rbytes == $wbytes) or die "short write on FTP data connection ($wbytes < $rbytes)";
$fwsize -= $len;
print STDERR ".";
}
$dc->close();
print STDERR " done.\n";
#
# Reboot
#
print STDERR "Rebooting device.\n";
$ftp->reboot();

View File

@@ -0,0 +1,209 @@
#!/usr/bin/env perl
#
# D-Link DSL-G6x4T flash utility
#
# Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
# based on fbox recovery util by Enrik Berkhan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
use IO::Socket::INET;
use IO::Select;
use Socket;
use strict;
use warnings;
sub usage() {
print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
exit 0;
}
my $ip = shift @ARGV;
$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
my $setip = unpack("N", inet_aton($ip));
$setip > 0 or usage();
my @packets;
foreach my $ver ([18, 1], [22, 2]) {
push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
}
print STDERR "Looking for device: ";
my $scanning;
my $box;
my $probe = IO::Socket::INET->new(Proto => 'udp',
Broadcast => 1,
LocalAddr => $ip,
LocalPort => 5035) or die "socket: $!";
my $sel = IO::Select->new($probe);
my $packet = pack("vCCVNV", 0, 18, 1, 1, 0, 0);
my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
$probe->send($packet, 0, $broadcast);
scan_again:
print "Looking for Fritz!Box ";
my @boxes = ();
my $peer;
$scanning = 100;
print "o";
while($scanning) {
my $reply;
my @ready;
if (@ready = $sel->can_read(0.2)) {
$peer = $probe->recv($reply, 16);
next if (length($reply) < 16);
my ($port, $addr) = sockaddr_in($peer);
my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
$addr2 = pack("N", $addr2);
if ($code == 2) {
print "O";
push @boxes, [$major, $minor1, $minor2, $addr, $addr2];
$scanning = 2 if ($scanning > 2);
}
} else {
$scanning--;
if (scalar @boxes == 0) {
$probe->send($packet, 0, $broadcast);
print "o";
} else {
print ".";
}
}
}
if (scalar @boxes == 0) {
print " none found, giving up.\n";
exit 1;
} else {
print " found!\n";
}
{
package ADAM2FTP;
use base qw(Net::FTP);
# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
sub _USER { shift->command("USER",@_)->response() }
sub _PASV { shift->command("P\@SW")->response() == Net::FTP::CMD_OK }
sub _GETENV {
my $ftp = shift;
my ($ok, $name, $value);
$ftp->command("GETENV",@_);
while(length($ok = $ftp->response()) < 1) {
my $line = $ftp->getline();
unless (defined($value)) {
chomp($line);
($name, $value) = split(/\s+/, $line, 2);
}
}
$ftp->debug_print(0, "getenv: $value\n")
if $ftp->debug();
return $value;
}
sub getenv {
my $ftp = shift;
my $name = shift;
return $ftp->_GETENV($name);
}
sub _REBOOT { shift->command("REBOOT")->response() == Net::FTP::CMD_OK }
sub reboot {
my $ftp = shift;
$ftp->_REBOOT;
$ftp->close;
}
sub check {
my $ftp = shift;
delete ${*$ftp}{'net_ftp_port'};
delete ${*$ftp}{'net_ftp_pasv'};
my $data = $ftp->_data_cmd('CHECK' ,@_) or return undef;
my $sum;
if (${${*$ftp}{'net_cmd_resp'}}[0] =~ /^Flash check 0x([0-9A-F]{8})/) {
$sum = hex($1);
}
$data->_close();
return $sum;
}
}
# passive mode geht mit Net::FTP nicht, connected zu spaet fuer ADAM2!
my $ftp = ADAM2FTP->new($ip, Passive => 0, Debug => 0, Timeout => 600)
or die "can't FTP ADAM2";
$ftp->login("adam2", "adam2") or die "can't login adam2";
$ftp->binary();
my $pid = $ftp->getenv('ProductID');
my $hwrev = $ftp->getenv('HWRevision');
my $fwrev = $ftp->getenv('firmware_info');
my $ulrev = $ftp->getenv('urlader-version');
print "Product ID: $pid\n";
print "Hardware Revision: $hwrev\n";
print "Urlader Revision: $ulrev\n";
print "Firmware Revision: $fwrev\n";
$ftp->hash(\*STDOUT, 64 * 1024);
my $file = shift @ARGV;
$file || exit 0;
open FILE, "<$file" or die "can't open firmware file\n";
my $mtd0 = $ftp->getenv("mtd0");
my $mtd1 = $ftp->getenv("mtd1");
my ($ksize, $fssize);
$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
$ksize and $fssize or die 'cannot read partition offsets';
printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
$ftp->command("MEDIA FLSH")->response();
$ftp->binary();
print STDERR "Writing to mtd1...\n";
my $dc = $ftp->stor("fs mtd1");
$dc or die "can't open data connection\n";
my $rbytes = 1;
while (($ksize > 0) and ($rbytes > 0)) {
my $buffer;
my $len = ($ksize > 1024 ? 1024 : $ksize);
$rbytes = read FILE, $buffer, $len;
$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
}
$dc->close();
$rbytes or die "no more data left to write\n";
print STDERR "Writing to mtd0...\n";
$dc = $ftp->stor("fs mtd0");
$dc or die "can't open data connection\n";
while (($fssize > 0) and ($rbytes > 0)) {
my $buffer;
my $len = ($fssize > 1024 ? 1024 : $fssize);
$rbytes = read FILE, $buffer, $len;
$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
}
$dc->close();
$ftp->reboot();

174
scripts/flashing/adam2flash.pl Executable file
View File

@@ -0,0 +1,174 @@
#!/usr/bin/env perl
#
# D-Link DSL-G6x4T flash utility
#
# Copyright (C) 2005 Felix Fietkau <mailto@nbd.name>
# based on fbox recovery util by Enrik Berkhan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
use IO::Socket::INET;
use Socket;
use strict;
use warnings;
sub usage() {
print STDERR "Usage: $0 <ip> [firmware.bin]\n\n";
exit 0;
}
my $ip = shift @ARGV;
$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
my $probe = IO::Socket::INET->new(Proto => 'udp',
Broadcast => 1,
LocalPort => 5035) or die "socket: $!";
my $setip = unpack("N", inet_aton($ip));
$setip > 0 or usage();
my @packets;
foreach my $ver ([18, 1], [22, 2]) {
push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
}
print STDERR "Looking for device: ";
my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
my $scanning;
my $box;
$SIG{"ALRM"} = sub {
return if --$scanning <= 0;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
};
$scanning = 10;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
while($scanning) {
my $reply;
alarm(1);
if (my $peer = $probe->recv($reply, 16)) {
next if (length($reply) < 16);
my ($port, $addr) = sockaddr_in($peer);
my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVV", $reply);
$addr2 = pack("N", $addr2);
if ($code == 2) {
$scanning = 0;
printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr), inet_ntoa($addr2);
$box = inet_ntoa($addr);
}
}
}
$box or die " not found!\n";
{
package ADAM2FTP;
use base qw(Net::FTP);
# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
sub _USER {
shift->command("USER",@_)->response()
}
sub _GETENV {
my $ftp = shift;
my ($ok, $name, $value);
$ftp->command("GETENV",@_);
while(length($ok = $ftp->response()) < 1) {
my $line = $ftp->getline();
unless (defined($value)) {
chomp($line);
($name, $value) = split(/\s+/, $line, 2);
}
}
$ftp->debug_print(0, "getenv: $value\n")
if $ftp->debug();
return $value;
}
sub getenv {
my $ftp = shift;
my $name = shift;
return $ftp->_GETENV($name);
}
sub _REBOOT {
shift->command("REBOOT")->response() == Net::FTP::CMD_OK
}
sub reboot {
my $ftp = shift;
$ftp->_REBOOT;
$ftp->close;
}
}
my $file = shift @ARGV;
$file || exit 0;
open FILE, "<$file" or die "can't open firmware file\n";
my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
$ftp->login("adam2", "adam2") or die "can't login\n";
my $mtd0 = $ftp->getenv("mtd0");
my $mtd1 = $ftp->getenv("mtd1");
my ($ksize, $fssize);
$mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
$mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
$ksize and $fssize or die 'cannot read partition offsets';
printf STDERR "Available flash space: 0x%08x (0x%08x + 0x%08x)\n", $ksize + $fssize, $ksize, $fssize;
$ftp->command("MEDIA FLSH")->response();
$ftp->binary();
print STDERR "Writing to mtd1...\n";
my $dc = $ftp->stor("fs mtd1");
$dc or die "can't open data connection\n";
my $rbytes = 1;
while (($ksize > 0) and ($rbytes > 0)) {
my $buffer;
my $len = ($ksize > 1024 ? 1024 : $ksize);
$rbytes = read FILE, $buffer, $len;
$rbytes and $ksize -= $dc->write($buffer, $rbytes, 600);
}
$dc->close();
$rbytes or die "no more data left to write\n";
print STDERR "Writing to mtd0...\n";
$dc = $ftp->stor("fs mtd0");
$dc or die "can't open data connection\n";
while (($fssize > 0) and ($rbytes > 0)) {
my $buffer;
my $len = ($fssize > 1024 ? 1024 : $fssize);
$rbytes = read FILE, $buffer, $len;
$rbytes and $fssize -= $dc->write($buffer, $rbytes, 600);
}
$dc->close();
$ftp->reboot();

View File

@@ -0,0 +1,170 @@
#!/usr/bin/env perl
#
# Linksys ADSL2MUE Flash utility.
#
# Copyright (C) 2008 Alexandre Lissy <alexandrelissy@free.fr>
# based on D-Link DSL-G6x4T flash utility by Felix Fietkau <mailto@nbd.name>
# based on fbox recovery util by Enrik Berkhan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
use IO::Socket::INET;
use Socket;
use strict;
use warnings;
sub usage() {
print STDERR "Usage: $0 <ip> [firmware.bin] [partition]\n\n";
exit 0;
}
my $ip = shift @ARGV;
$ip and $ip =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ or usage();
my $probe = IO::Socket::INET->new(Proto => 'udp',
Broadcast => 1,
LocalPort => 5035) or die "socket: $!";
my $setip = unpack("N", inet_aton($ip));
$setip > 0 or usage();
my @packets;
foreach my $ver ([18, 1], [22, 2]) {
push @packets, pack("vCCVNV", 0, @$ver, 1, $setip, 0);
}
print STDERR "Looking for device: ";
my $broadcast = sockaddr_in(5035, INADDR_BROADCAST);
my $scanning;
my $box;
$SIG{"ALRM"} = sub {
return if --$scanning <= 0;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
};
$scanning = 10;
foreach my $packet (@packets) {
$probe->send($packet, 0, $broadcast);
}
print STDERR ".";
while($scanning) {
my $reply;
alarm(1);
if (my $peer = $probe->recv($reply, 16)) {
next if (length($reply) < 16);
my ($port, $addr) = sockaddr_in($peer);
my ($major, $minor1, $minor2, $code, $addr2) = unpack("vCCVN", $reply);
$addr2 = pack("N", $addr2);
if ($code == 1) {
$scanning = 0;
printf STDERR " found!\nADAM2 version $major.$minor1.$minor2 at %s (%s)\n", inet_ntoa($addr2), inet_ntoa($addr);
$box = inet_ntoa($addr2);
}
}
}
$box or die " not found!\n";
{
package ADAM2FTP;
use base qw(Net::FTP);
# ADAM2 requires upper case commands, some brain dead firewall doesn't ;-)
sub _USER {
shift->command("USER",@_)->response()
}
sub _GETENV {
my $ftp = shift;
my ($ok, $name, $value);
$ftp->command("GETENV",@_);
while(length($ok = $ftp->response()) < 1) {
my $line = $ftp->getline();
unless (defined($value)) {
chomp($line);
($name, $value) = split(/\s+/, $line, 2);
}
}
$ftp->debug_print(0, "getenv: $value\n")
if $ftp->debug();
return $value;
}
sub getenv {
my $ftp = shift;
my $name = shift;
return $ftp->_GETENV($name);
}
sub _REBOOT {
shift->command("REBOOT")->response() == Net::FTP::CMD_OK
}
sub reboot {
my $ftp = shift;
$ftp->_REBOOT;
$ftp->close;
}
}
my $file = shift @ARGV;
my $part = shift @ARGV;
$file || exit 0;
$part || exit 0;
open FILE, "<$file" or die "can't open firmware file\n";
my $ftp = ADAM2FTP->new($box, Debug => 0, Timeout => 600) or die "can't open control connection\n";
$ftp->login("adam2", "adam2") or die "can't login\n";
# my $mtd0 = $ftp->getenv("mtd0");
# my $mtd1 = $ftp->getenv("mtd1");
my $mtd4 = $ftp->getenv($part);
# my ($ksize, $fssize);
my ($ossize, $mtd_start, $mtd_end);
# $mtd1 =~ /^(0x\w+),(0x\w+)$/ and $ksize = hex($2) - hex($1);
# $mtd0 =~ /^(0x\w+),(0x\w+)$/ and $fssize = hex($2) - hex($1);
$mtd4 =~ /^(0x\w+),(0x\w+)$/;
$ossize = hex($2) - hex($1);
$mtd_start = hex($1);
$mtd_end = hex($2);
$ossize and $mtd_start and $mtd_end or die 'cannot read partition offsets';
printf STDERR "Available flash space: 0x%08x ($part: 0x%08x to 0x%08x)\n", $ossize, $mtd_start, $mtd_end;
$ftp->command("MEDIA FLSH")->response();
$ftp->binary();
print STDERR "Writing to $part ...\n";
my $dc = $ftp->stor("data $part");
$dc or die "can't open data connection\n";
my $rbytes = 1;
while (($ossize > 0) and ($rbytes > 0)) {
my $buffer;
my $len = ($ossize > 1024 ? 1024 : $ossize);
$rbytes = read FILE, $buffer, $len;
printf STDERR ".";
$rbytes and $ossize -= $dc->write($buffer, $rbytes, 600);
}
printf STDERR "\nDone.\n";
$dc->close();

45
scripts/flashing/eva_ramboot.py Executable file
View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python3
import argparse
from ftplib import FTP
from sys import argv
from os import stat
parser = argparse.ArgumentParser(description='Tool to boot AVM EVA ramdisk images.')
parser.add_argument('ip', type=str, help='IP-address to transfer the image to')
parser.add_argument('image', type=str, help='Location of the ramdisk image')
parser.add_argument('--offset', type=lambda x: int(x,0), help='Offset to load the image to in hex format with leading 0x. Only needed for non-lantiq devices.')
args = parser.parse_args()
size = stat(args.image).st_size
# arbitrary size limit, to prevent the address calculations from overflows etc.
assert size < 0x2000000
if args.offset:
addr = size
haddr = args.offset
else:
# We need to align the address.
# A page boundary seems to be sufficient on 7362sl and 7412
addr = ((0x8000000 - size) & ~0xfff)
haddr = 0x80000000 + addr
img = open(args.image, "rb")
ftp = FTP(args.ip, 'adam2', 'adam2')
def adam(cmd):
print("> %s"%(cmd))
resp = ftp.sendcmd(cmd)
print("< %s"%(resp))
assert resp[0:3] == "200"
ftp.set_pasv(True)
# The following parameters allow booting the avm recovery system with this
# script.
adam('SETENV memsize 0x%08x'%(addr))
adam('SETENV kernel_args_tmp mtdram1=0x%08x,0x88000000'%(haddr))
adam('MEDIA SDRAM')
ftp.storbinary('STOR 0x%08x 0x88000000'%(haddr), img)
img.close()
ftp.close()

66
scripts/flashing/flash.sh Executable file
View File

@@ -0,0 +1,66 @@
#!/bin/bash
#
# tftp flash script for wireless routers
#
# Copyright (C) 2004 by Oleg I. Vdovikin <oleg@cs.msu.su>
# Copyright (C) 2005 by Waldemar Brodkorb <wbx@openwrt.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
if [ -z "$1" ] || [ ! -f $1 ] || [ -z $2 ]; then
echo Usage: $0 firmware vendor
cat << EOF
IMPORTANT:
Notes for Linksys / Asus WL500gx router:
be sure you have set boot_wait to yes. Power on your router
after executing this script.
Notes for Asus WL500g router:
be sure POWER led is flashing (If this is not the case
poweroff the device, push the reset button & power on
it again, then release button)
1) connect your pc to the LAN port
2) be sure your link is up and has an address in the
192.168.1.0/24 address range (and not the 192.168.1.1)
Notes for Toshiba router:
boot_wait is enabled by default on these units.
1) connect your pc to any of the four LAN ports
2) be sure your link is up and has an address in the
192.168.10.1/24 address range (and not the 192.168.10.1)
3) run this script (unit will only accept .trx images)
4) Turn unit power on.
EOF
exit 0
fi
if [ "$2" = "asus" ]; then
echo Confirming IP address setting...
echo -en "get ASUSSPACELINK\x01\x01\xa8\xc0 /dev/null\nquit\n" | tftp 192.168.1.1
echo Flashing 192.168.1.1 using $1...
echo -en "binary\nput $1 ASUSSPACELINK\nquit\n" | tftp 192.168.1.1
echo Please wait until leds stops flashing.
elif [ "$2" = "linksys" ]; then
echo Flashing 192.168.1.1 using $1...
echo -en "rexmt 1\ntrace\nbinary\nput $1\nquit\n" | tftp 192.168.1.1
echo Please wait until power led stops flashing. Do not poweroff! Then you can login via telnet 192.168.1.1.
elif [ "$2" = "toshiba" ]; then
echo Flashing 192.168.10.1 using $1...
echo -en "rexmt 1\ntrace\nbinary\nput $1\nquit\n" | tftp 192.168.10.1
echo Unit will automatically reboot within 5 minutes. Do not power off. Then you can login via telnet 192.168.10.1.
fi

283
scripts/flashing/jungo-image.py Executable file
View File

@@ -0,0 +1,283 @@
#!/usr/bin/env python
#
# Copyright 2008, 2009 (C) Jose Vasconcellos <jvasco@verizon.net>
#
# A script that can communicate with jungo-based routers
# (such as MI424-WR, USR8200 and WRV54G) to backup the installed
# firmware and replace the boot loader.
#
# Tested with Python 2.5 on Linux and Windows
#
"""Usage: %s [options] <IP_address> [image.bin | url]
Valid options:
\t-h | --help: usage statement
\t-d | --dump: create a flash dump
\t-f | --file: use <filename> to store dump contents
\t-u | --user: provide username (default admin)
\t-p | --pass: provide password (default password1)
\t --port: set port for http (default 8080)
\t-q | --quiet: don't display unnecessary information
\t-r | --reboot: reboot target on successful transfer
\t-V | --version: display version information
If no image (or url) is given, a flash dump is created.
A built-in http server is used when an image file is provided.
"""
import os
import sys
import getopt
import getpass
import telnetlib
import string
import binascii
import socket
import thread
import SocketServer
import SimpleHTTPServer
reboot = 0
HOST = "192.168.1.1"
PORT = 8080
user = "admin"
#password = getpass.getpass()
password = "password1"
proto = "http"
url = ""
imagefile = ""
dumpfile = ""
verbose = 1
do_dump = 0
dumplen = 0x10000
flashsize=4*1024*1024
#device="br0"
device="ixp0"
####################
def start_server(server):
httpd = SocketServer.TCPServer((server,PORT),SimpleHTTPServer.SimpleHTTPRequestHandler)
thread.start_new_thread(httpd.serve_forever,())
####################
def get_flash_size():
# make sure we don't have an A0 stepping
tn.write("cat /proc/cpuinfo\n")
buf = tn.read_until("Returned 0", 3)
if not buf:
print "Unable to obtain CPU information; make sure to not use A0 stepping!"
elif buf.find('rev 0') > 0:
print "Warning: IXP42x stepping A0 detected!"
if imagefile or url:
print "Error: No linux support for A0 stepping!"
sys.exit(2)
# now get flash size
tn.write("cat /proc/mtd\n")
buf = tn.read_until("Returned 0", 3)
if buf:
i = buf.find('mtd0:')
if i > 0:
return int(buf[i+6:].split()[0],16)
# use different command
tn.write("flash_layout\n")
buf = tn.read_until("Returned 0", 3)
i = buf.rfind('Range ')
if i > 0:
return int(buf[i+17:].split()[0],16)
print "Can't determine flash size!"
else:
print "Unable to obtain flash size!"
sys.exit(2)
def image_dump(tn, dumpfile):
if not dumpfile:
tn.write("ver\n");
buf = tn.read_until("Returned 0",2)
i = buf.find("Platform:")
if i < 0:
platform="jungo"
else:
line=buf[i+9:]
i=line.find('\n')
platform=line[:i].split()[-1]
tn.write("rg_conf_print /dev/%s/mac\n" % device);
buf = tn.read_until("Returned 0",3)
i = buf.find("mac(")
if i > 0:
i += 4
else:
print "No MAC address found! (use -f option)"
sys.exit(1)
dumpfile = "%s-%s.bin" % (platform, buf[i:i+17].replace(':',''))
else:
tn.write("\n")
print "Dumping flash contents (%dMB) to %s" % (flashsize/1048576, dumpfile)
f = open(dumpfile, "wb")
t=flashsize/dumplen
for addr in range(t):
if verbose:
sys.stdout.write('\r%d%%'%(100*addr/t))
sys.stdout.flush()
tn.write("flash_dump -r 0x%x -l %d -4\n" % (addr*dumplen, dumplen))
tn.read_until("\n")
count = addr*dumplen
while 1:
buf = tn.read_until("\n")
if buf.strip() == "Returned 0":
break
s = buf.split()
if s and s[0][-1] == ':':
a=int(s[0][:-1],16)
if a != count:
print "Format error: %x != %x"%(a,count)
sys.exit(2)
count += 16
f.write(binascii.a2b_hex(string.join(s[1:],'')))
tn.read_until(">",1)
f.close()
if verbose:
print ""
def telnet_option(sock,cmd,option):
#print "Option: %d %d" % (ord(cmd), ord(option))
if cmd == telnetlib.DO:
c=telnetlib.WILL
elif cmd == telnetlib.WILL:
c=telnetlib.DO
sock.sendall(telnetlib.IAC + c + option)
def telnet_timeout():
print "Fatal error: telnet timeout!"
sys.exit(1)
def usage():
print __doc__ % os.path.basename(sys.argv[0])
####################
try:
opts, args = getopt.getopt(sys.argv[1:], "hdf:qp:P:rvV", \
["help", "dump", "file=", "user=", "pass=", "port=",
"quiet=", "reboot", "verbose", "version"])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(1)
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit(1)
elif o in ("-V", "--version"):
print "%s: 0.11" % sys.argv[0]
sys.exit(1)
elif o in ("-d", "--no-dump"):
do_dump = 1
elif o in ("-f", "--file"):
dumpfile = a
elif o in ("-u", "--user"):
user = a
elif o in ("-p", "--pass"):
password = a
elif o == "--port":
PORT = int(a)
elif o in ("-q", "--quiet"):
verbose = 0
elif o in ("-r", "--reboot"):
reboot = 1
elif o in ("-v", "--verbose"):
verbose = 1
# make sure we have enough arguments
if len(args) > 0:
HOST = args[0]
if len(args) == 2:
if args[1].split(':')[0] in ("tftp", "http", "ftp"):
url = args[1]
else:
imagefile = args[1]
else:
do_dump = 1;
####################
# create a telnet session to the router
try:
tn = telnetlib.Telnet(HOST)
except socket.error, msg:
print "Unable to establish telnet session to %s: %s" % (HOST, msg)
sys.exit(1)
tn.set_option_negotiation_callback(telnet_option)
buf = tn.read_until("Username: ", 3)
if not buf:
telnet_timeout()
tn.write(user+"\n")
if password:
buf = tn.read_until("Password: ", 3)
if not buf:
telnet_timeout()
tn.write(password+"\n")
# wait for prompt
buf = tn.read_until("> ", 3)
if not buf:
telnet_timeout()
flashsize = get_flash_size()
if do_dump:
image_dump(tn, dumpfile)
if imagefile or url:
splitpath = os.path.split(imagefile)
# create load command
if url:
cmd = "load -u %s -r 0\n" % (url)
else:
server = tn.get_socket().getsockname()[0]
cmd = "load -u http://%s:%d/%s -r 0\n" % (server, PORT, splitpath[1])
if not os.access(imagefile, os.R_OK):
print "File access error: %s" % (imagefile)
sys.exit(3)
# make sure we're in the directory where the image is located
if splitpath[0]:
os.chdir(splitpath[0])
start_server(server)
if verbose:
print "Unlocking flash..."
tn.write("unlock 0 0x%x\n" % flashsize)
buf = tn.read_until("Returned 0",5)
if verbose:
print "Writing new image..."
print cmd,
tn.write(cmd)
buf = tn.read_until("Returned 0",10)
# wait till the transfer completed
buf = tn.read_until("Download completed successfully",20)
if buf:
print "Flash update complete!"
if reboot:
tn.write("reboot\n")
print "Rebooting..."
tn.write("exit\n")
tn.close()

33
scripts/gen-dependencies.sh Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Copyright (C) 2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
SELF=${0##*/}
READELF="${READELF:-readelf}"
OBJCOPY="${OBJCOPY:-objcopy}"
TARGETS=$*
XARGS="${XARGS:-xargs -r}"
[ -z "$TARGETS" ] && {
echo "$SELF: no directories / files specified"
echo "usage: $SELF [PATH...]"
exit 1
}
find $TARGETS -type f -a -exec file {} \; | \
sed -n -e 's/^\(.*\):.*ELF.*\(executable\|shared object\).*,.*/\1/p' | \
$XARGS -n1 $READELF -d | \
awk '$2 ~ /NEEDED/ && $NF !~ /interpreter/ && $NF ~ /^\[?lib.*\.so/ { gsub(/[\[\]]/, "", $NF); print $NF }' | \
sort -u
tmp=`mktemp $TMP_DIR/dep.XXXXXXXX`
for kmod in `find $TARGETS -type f -name \*.ko`; do
$OBJCOPY -O binary -j .modinfo $kmod $tmp
sed -e 's,\x00,\n,g' $tmp | \
sed -ne '/^depends=.\+/ { s/^depends=//; s/,/.ko\n/g; s/$/.ko/p; q }'
done | sort -u
rm -f $tmp

35
scripts/gen_image_generic.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Copyright (C) 2006-2012 OpenWrt.org
set -e -x
[ $# == 5 -o $# == 6 ] || {
echo "SYNTAX: $0 <file> <kernel size> <kernel directory> <rootfs size> <rootfs image> [<align>]"
exit 1
}
OUTPUT="$1"
KERNELSIZE="$2"
KERNELDIR="$3"
ROOTFSSIZE="$4"
ROOTFSIMAGE="$5"
ALIGN="$6"
rm -f "$OUTPUT"
head=16
sect=63
cyl=$(( ($KERNELSIZE + $ROOTFSSIZE) * 1024 * 1024 / ($head * $sect * 512)))
# create partition table
set `ptgen -o "$OUTPUT" -h $head -s $sect -p ${KERNELSIZE}m -p ${ROOTFSSIZE}m ${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE}`
KERNELOFFSET="$(($1 / 512))"
KERNELSIZE="$2"
ROOTFSOFFSET="$(($3 / 512))"
ROOTFSSIZE="$(($4 / 512))"
[ -n "$PADDING" ] && dd if=/dev/zero of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc count="$ROOTFSSIZE"
dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 seek="$ROOTFSOFFSET" conv=notrunc
make_ext4fs -J -l "$KERNELSIZE" "$OUTPUT.kernel" "$KERNELDIR"
dd if="$OUTPUT.kernel" of="$OUTPUT" bs=512 seek="$KERNELOFFSET" conv=notrunc
rm -f "$OUTPUT.kernel"

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env bash
export LANG=C
export LC_ALL=C
[ -n "$TOPDIR" ] && cd $TOPDIR
try_version() {
[ -f version.date ] || return 1
SOURCE_DATE_EPOCH="$(cat version.date)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_git() {
[ -e .git ] || return 1
SOURCE_DATE_EPOCH="$(git log -1 --format=format:%ct)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_hg() {
[ -d .hg ] || return 1
SOURCE_DATE_EPOCH="$(hg log --template '{date}' -l 1 | cut -d. -f1)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_mtime() {
perl -e 'print((stat $ARGV[0])[9])' "$0"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_version || try_git || try_hg || try_mtime || SOURCE_DATE_EPOCH=""
echo "$SOURCE_DATE_EPOCH"

59
scripts/getver.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
export LANG=C
export LC_ALL=C
[ -n "$TOPDIR" ] && cd $TOPDIR
GET_REV=$1
try_version() {
[ -f version ] || return 1
REV="$(cat version)"
[ -n "$REV" ]
}
try_git() {
REBOOT=ee53a240ac902dc83209008a2671e7fdcf55957a
git rev-parse --git-dir >/dev/null 2>&1 || return 1
[ -n "$GET_REV" ] || GET_REV="HEAD"
case "$GET_REV" in
r*)
GET_REV="$(echo $GET_REV | tr -d 'r')"
BASE_REV="$(git rev-list ${REBOOT}..HEAD | wc -l | awk '{print $1}')"
REV="$(git rev-parse HEAD~$((BASE_REV - GET_REV)))"
;;
*)
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
ORIGIN="$(git rev-parse --verify --symbolic-full-name ${BRANCH}@{u} 2>/dev/null)"
[ -n "$ORIGIN" ] || ORIGIN="$(git rev-parse --verify --symbolic-full-name openwrt-19.07@{u} 2>/dev/null)"
REV="$(git rev-list ${REBOOT}..$GET_REV | wc -l | awk '{print $1}')"
if [ -n "$ORIGIN" ]; then
UPSTREAM_BASE="$(git merge-base $GET_REV $ORIGIN)"
UPSTREAM_REV="$(git rev-list ${REBOOT}..$UPSTREAM_BASE | wc -l | awk '{print $1}')"
else
UPSTREAM_REV=0
fi
if [ "$REV" -gt "$UPSTREAM_REV" ]; then
REV="${UPSTREAM_REV}+$((REV - UPSTREAM_REV))"
fi
REV="${REV:+r$REV-$(git log -n 1 --format="%h" $UPSTREAM_BASE)}"
;;
esac
[ -n "$REV" ]
}
try_hg() {
[ -d .hg ] || return 1
REV="$(hg log -r-1 --template '{desc}' | awk '{print $2}' | sed 's/\].*//')"
REV="${REV:+r$REV}"
[ -n "$REV" ]
}
try_version || try_git || try_hg || REV="unknown"
echo "$REV"

166
scripts/ipkg-build Executable file
View File

@@ -0,0 +1,166 @@
#!/bin/sh
# ipkg-build -- construct a .ipk from a directory
# Carl Worth <cworth@east.isi.edu>
# based on a script by Steve Redler IV, steve@sr-tech.com 5-21-2001
# 2003-04-25 rea@sr.unh.edu
# Updated to work on Familiar Pre0.7rc1, with busybox tar.
# Note it Requires: binutils-ar (since the busybox ar can't create)
# For UID debugging it needs a better "find".
set -e
version=1.0
FIND="$(which find)"
FIND="${FIND:-$(which gfind)}"
TAR="${TAR:-$(which tar)}"
GZIP="$(which gzip)"
# try to use fixed source epoch
if [ -n "$SOURCE_DATE_EPOCH" ]; then
TIMESTAMP=$(date --date="@$SOURCE_DATE_EPOCH")
# look up date of last commit
elif [ -d "$TOPDIR/.git" ]; then
GIT="$(which git)"
TIMESTAMP=$(cd $TOPDIR; $GIT log -1 -s --format=%ci)
elif [ -d "$TOPDIR/.svn" ]; then
SVN="$(which svn)"
TIMESTAMP=$($SVN info "$TOPDIR" | sed -n "s/^Last Changed Date: \(.*\)/\1/p")
else
TIMESTAMP=$(date)
fi
ipkg_extract_value() {
sed -e "s/^[^:]*:[[:space:]]*//"
}
required_field() {
field=$1
grep "^$field:" < $CONTROL/control | ipkg_extract_value
}
pkg_appears_sane() {
local pkg_dir=$1
local owd=$PWD
cd $pkg_dir
PKG_ERROR=0
pkg=`required_field Package`
version=`required_field Version | sed 's/Version://; s/^.://g;'`
arch=`required_field Architecture`
if echo $pkg | grep '[^a-zA-Z0-9_.+-]'; then
echo "*** Error: Package name $name contains illegal characters, (other than [a-z0-9.+-])" >&2
PKG_ERROR=1;
fi
if [ -f $CONTROL/conffiles ]; then
rm -f $CONTROL/conffiles.resolved
for cf in `$FIND $(sed -e "s!^/!$pkg_dir/!" $CONTROL/conffiles) -type f`; do
echo "${cf#$pkg_dir}" >> $CONTROL/conffiles.resolved
done
rm $CONTROL/conffiles
if [ -f $CONTROL/conffiles.resolved ]; then
mv $CONTROL/conffiles.resolved $CONTROL/conffiles
chmod 0644 $CONTROL/conffiles
fi
fi
cd $owd
return $PKG_ERROR
}
###
# ipkg-build "main"
###
ogargs=""
noclean=0
usage="Usage: $0 [-c] [-C] [-o owner] [-g group] <pkg_directory> [<destination_directory>]"
while getopts "cg:ho:v" opt; do
case $opt in
o ) owner=$OPTARG
ogargs="--owner=$owner"
;;
g ) group=$OPTARG
ogargs="$ogargs --group=$group"
;;
c ) ;;
C ) noclean=1;;
v ) echo $version
exit 0
;;
h ) echo $usage >&2 ;;
\? ) echo $usage >&2
esac
done
shift $(($OPTIND - 1))
# continue on to process additional arguments
case $# in
1)
dest_dir=$PWD
;;
2)
dest_dir=$2
if [ "$dest_dir" = "." -o "$dest_dir" = "./" ] ; then
dest_dir=$PWD
fi
;;
*)
echo $usage >&2
exit 1
;;
esac
pkg_dir=$1
if [ ! -d $pkg_dir ]; then
echo "*** Error: Directory $pkg_dir does not exist" >&2
exit 1
fi
# CONTROL is second so that it takes precedence
CONTROL=
[ -d $pkg_dir/CONTROL ] && CONTROL=CONTROL
if [ -z "$CONTROL" ]; then
echo "*** Error: Directory $pkg_dir has no CONTROL subdirectory." >&2
exit 1
fi
if ! pkg_appears_sane $pkg_dir; then
echo >&2
echo "ipkg-build: Please fix the above errors and try again." >&2
exit 1
fi
tmp_dir=$dest_dir/IPKG_BUILD.$$
mkdir $tmp_dir
echo $CONTROL > $tmp_dir/tarX
# Preserve permissions (-p) when creating data.tar.gz as non-root user
( cd $pkg_dir && $TAR $ogargs -X $tmp_dir/tarX --format=gnu --sort=name -cpf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/data.tar.gz )
installed_size=`stat -c "%s" $tmp_dir/data.tar.gz`
sed -i -e "s/^Installed-Size: .*/Installed-Size: $installed_size/" \
$pkg_dir/$CONTROL/control
( cd $pkg_dir/$CONTROL && $TAR $ogargs --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" . | $GZIP -n - > $tmp_dir/control.tar.gz )
rm $tmp_dir/tarX
echo "2.0" > $tmp_dir/debian-binary
pkg_file=$dest_dir/${pkg}_${version}_${arch}.ipk
rm -f $pkg_file
( cd $tmp_dir && $TAR $ogargs --format=gnu --sort=name -cf - --mtime="$TIMESTAMP" ./debian-binary ./data.tar.gz ./control.tar.gz | $GZIP -n - > $pkg_file )
rm $tmp_dir/debian-binary $tmp_dir/data.tar.gz $tmp_dir/control.tar.gz
rmdir $tmp_dir
echo "Packaged contents of $pkg_dir into $pkg_file"

31
scripts/ipkg-make-index.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -e
pkg_dir=$1
if [ -z $pkg_dir ] || [ ! -d $pkg_dir ]; then
echo "Usage: ipkg-make-index <package_directory>" >&2
exit 1
fi
empty=1
for pkg in `find $pkg_dir -name '*.ipk' | sort`; do
empty=
name="${pkg##*/}"
name="${name%%_*}"
[[ "$name" = "kernel" ]] && continue
[[ "$name" = "libc" ]] && continue
echo "Generating index for package $pkg" >&2
file_size=$(stat -L -c%s $pkg)
sha256sum=$(mkhash sha256 $pkg)
# Take pains to make variable value sed-safe
sed_safe_pkg=`echo $pkg | sed -e 's/^\.\///g' -e 's/\\//\\\\\\//g'`
tar -xzOf $pkg ./control.tar.gz | tar xzOf - ./control | sed -e "s/^Description:/Filename: $sed_safe_pkg\\
Size: $file_size\\
SHA256sum: $sha256sum\\
Description:/"
echo ""
done
[ -n "$empty" ] && echo
exit 0

20
scripts/ipkg-remove Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
sourcename="$1"; shift
for pkg in "$@"; do
tar -Ozxf "$pkg" ./control.tar.gz 2>/dev/null | tar -Ozxf - ./control 2>/dev/null | \
while read field value; do
if [ "$field" = "SourceName:" ] && [ "$value" = "$sourcename" ]; then
rm -vf "$pkg"
break
fi
done
case "$pkg" in
*/"${sourcename}_"*.ipk)
rm -vf "$pkg"
;;
esac
done
exit 0

52
scripts/json_add_image_info.py Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
from os import getenv
from pathlib import Path
from sys import argv
import hashlib
import json
if len(argv) != 2:
print("ERROR: JSON info script requires output arg")
exit(1)
json_path = Path(argv[1])
bin_dir = Path(getenv("BIN_DIR"))
image_file = bin_dir / getenv("IMAGE_NAME")
if not image_file.is_file():
print("Skip JSON creation for non existing image ", image_file)
exit(0)
def get_titles():
return [{"title": getenv("DEVICE_TITLE")}]
device_id = getenv("DEVICE_ID")
image_hash = hashlib.sha256(image_file.read_bytes()).hexdigest()
image_info = {
"metadata_version": 1,
"target": "{}/{}".format(getenv("TARGET"), getenv("SUBTARGET")),
"version_code": getenv("VERSION_CODE"),
"version_number": getenv("VERSION_NUMBER"),
"profiles": {
device_id: {
"image_prefix": getenv("IMAGE_PREFIX"),
"images": [
{
"type": getenv("IMAGE_TYPE"),
"filesystem": getenv("IMAGE_FILESYSTEM"),
"name": getenv("IMAGE_NAME"),
"sha256": image_hash,
}
],
"device_packages": getenv("DEVICE_PACKAGES").split(),
"supported_devices": getenv("SUPPORTED_DEVICES").split(),
"titles": get_titles(),
}
},
}
json_path.write_text(json.dumps(image_info, separators=(",", ":")))

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
from os import getenv, environ
from pathlib import Path
from subprocess import run, PIPE
from sys import argv
import json
if len(argv) != 2:
print("JSON info files script requires ouput file as argument")
exit(1)
output_path = Path(argv[1])
assert getenv("WORK_DIR"), "$WORK_DIR required"
work_dir = Path(getenv("WORK_DIR"))
output = {}
for json_file in work_dir.glob("*.json"):
image_info = json.loads(json_file.read_text())
if not output:
output.update(image_info)
else:
# get first (and only) profile in json file
device_id = next(iter(image_info["profiles"].keys()))
if device_id not in output["profiles"]:
output["profiles"].update(image_info["profiles"])
else:
output["profiles"][device_id]["images"].append(
image_info["profiles"][device_id]["images"][0]
)
if output:
default_packages, output["arch_packages"] = run(
[
"make",
"--no-print-directory",
"-C",
"target/linux/{}".format(output['target'].split('/')[0]),
"val.DEFAULT_PACKAGES",
"val.ARCH_PACKAGES",
],
stdout=PIPE,
stderr=PIPE,
check=True,
env=environ.copy().update({"TOPDIR": Path().cwd()}),
universal_newlines=True,
).stdout.splitlines()
output["default_packages"] = default_packages.split()
output_path.write_text(json.dumps(output, sort_keys=True, separators=(",", ":")))
else:
print("JSON info file script could not find any JSON files for target")

182
scripts/kconfig.pl Executable file
View File

@@ -0,0 +1,182 @@
#!/usr/bin/env perl
#
# Copyright (C) 2006 Felix Fietkau <nbd@nbd.name>
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
use warnings;
use strict;
my @arg;
my $PREFIX = "CONFIG_";
sub set_config($$$$) {
my $config = shift;
my $idx = shift;
my $newval = shift;
my $mod_plus = shift;
if (!defined($config->{$idx}) or !$mod_plus or
$config->{$idx} eq '#undef' or $newval eq 'y') {
$config->{$idx} = $newval;
}
}
sub load_config($$) {
my $file = shift;
my $mod_plus = shift;
my %config;
open FILE, "$file" or die "can't open file '$file'";
while (<FILE>) {
chomp;
/^$PREFIX(.+?)=(.+)/ and do {
set_config(\%config, $1, $2, $mod_plus);
next;
};
/^# $PREFIX(.+?) is not set/ and do {
set_config(\%config, $1, "#undef", $mod_plus);
next;
};
/^#/ and next;
/^(.+)$/ and warn "WARNING: can't parse line: $1\n";
}
return \%config;
}
sub config_and($$) {
my $cfg1 = shift;
my $cfg2 = shift;
my %config;
foreach my $config (keys %$cfg1) {
my $val1 = $cfg1->{$config};
my $val2 = $cfg2->{$config};
$val2 and ($val1 eq $val2) and do {
$config{$config} = $val1;
};
}
return \%config;
}
sub config_add($$$) {
my $cfg1 = shift;
my $cfg2 = shift;
my $mod_plus = shift;
my %config;
for ($cfg1, $cfg2) {
my %cfg = %$_;
foreach my $config (keys %cfg) {
if ($mod_plus and $config{$config}) {
next if $config{$config} eq "y";
next if $cfg{$config} eq '#undef';
}
$config{$config} = $cfg{$config};
}
}
return \%config;
}
sub config_diff($$$) {
my $cfg1 = shift;
my $cfg2 = shift;
my $new_only = shift;
my %config;
foreach my $config (keys %$cfg2) {
if (!defined($cfg1->{$config}) or $cfg1->{$config} ne $cfg2->{$config}) {
next if $new_only and !defined($cfg1->{$config}) and $cfg2->{$config} eq '#undef';
$config{$config} = $cfg2->{$config};
}
}
return \%config
}
sub config_sub($$) {
my $cfg1 = shift;
my $cfg2 = shift;
my %config = %{$cfg1};
foreach my $config (keys %$cfg2) {
delete $config{$config};
}
return \%config;
}
sub print_cfgline($$) {
my $name = shift;
my $val = shift;
if ($val eq '#undef' or $val eq 'n') {
print "# $PREFIX$name is not set\n";
} else {
print "$PREFIX$name=$val\n";
}
}
sub dump_config($) {
my $cfg = shift;
die "argument error in dump_config" unless ($cfg);
my %config = %$cfg;
foreach my $config (sort keys %config) {
print_cfgline($config, $config{$config});
}
}
sub parse_expr {
my $pos = shift;
my $mod_plus = shift;
my $arg = $arg[$$pos++];
die "Parse error" if (!$arg);
if ($arg eq '&') {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos);
return config_and($arg1, $arg2);
} elsif ($arg =~ /^\+/) {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos);
return config_add($arg1, $arg2, 0);
} elsif ($arg =~ /^m\+/) {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos, 1);
return config_add($arg1, $arg2, 1);
} elsif ($arg eq '>') {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos);
return config_diff($arg1, $arg2, 0);
} elsif ($arg eq '>+') {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos);
return config_diff($arg1, $arg2, 1);
} elsif ($arg eq '-') {
my $arg1 = parse_expr($pos);
my $arg2 = parse_expr($pos);
return config_sub($arg1, $arg2);
} else {
return load_config($arg, $mod_plus);
}
}
while (@ARGV > 0 and $ARGV[0] =~ /^-\w+$/) {
my $cmd = shift @ARGV;
if ($cmd =~ /^-n$/) {
$PREFIX = "";
} elsif ($cmd =~ /^-p$/) {
$PREFIX = shift @ARGV;
} else {
die "Invalid option: $cmd\n";
}
}
@arg = @ARGV;
my $pos = 0;
dump_config(parse_expr(\$pos));
die "Parse error" if ($arg[$pos]);

67
scripts/linksys-image.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/sh
#
# Copyright (C) 2018 Oceanic Systems (UK) Ltd
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# Maintained by: Ryan Pannell <ryan [at] o s u k l .com> <github.com/Escalion>
#
# Write Linksys signature for factory image
# This is appended to the factory image and is tested by the Linksys Upgrader - as observed in civic.
# The footer is 256 bytes. The format is:
# .LINKSYS. This is detected by the Linksys upgrader before continuing with upgrade. (9 bytes)
# <VERSION> The version number of upgrade. Not checked so use arbitary value (8 bytes)
# <TYPE> Model of target device, padded (0x20) to (15 bytes)
# <CRC> CRC checksum of the image to flash (8 byte)
# <padding> Padding (0x20) (7 bytes)
# <signature> Signature of signer. Not checked so use Arbitary value (16 bytes)
# <padding> Padding (0x00) (192 bytes)
# 0x0A (1 byte)
## version history
# * version 1: initial commit
set -e
ME="${0##*/}"
usage() {
echo "Usage: $ME <type> <in filename>"
[ "$IMG_OUT" ] && rm -f "$IMG_OUT"
exit 1
}
[ "$#" -lt 3 ] && usage
TYPE=$1
tmpdir="$( mktemp -d 2> /dev/null )"
if [ -z "$tmpdir" ]; then
# try OSX signature
tmpdir="$( mktemp -t 'ubitmp' -d )"
fi
if [ -z "$tmpdir" ]; then
exit 1
fi
trap "rm -rf $tmpdir" EXIT
IMG_TMP_OUT="${tmpdir}/out"
IMG_IN=$2
IMG_OUT="${IMG_IN}.new"
[ ! -f "$IMG_IN" ] && echo "$ME: Not a valid image: $IMG_IN" && usage
dd if="${IMG_IN}" of="${IMG_TMP_OUT}"
CRC=$(printf "%08X" $(dd if="${IMG_IN}" bs=$(stat -c%s "${IMG_IN}") count=1|cksum| cut -d ' ' -f1))
printf ".LINKSYS.01000409%-15s%-8s%-7s%-16s" "${TYPE}" "${CRC}" "" "K0000000F0246434" >> "${IMG_TMP_OUT}"
dd if=/dev/zero bs=1 count=192 conv=notrunc >> "${IMG_TMP_OUT}"
printf '\12' >> "${IMG_TMP_OUT}"
cp "${IMG_TMP_OUT}" "${IMG_OUT}"

21
scripts/make-ipkg-dir.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
BASE=http://svn.openwrt.org/openwrt/trunk/openwrt
TARGET=$1
CONTROL=$2
VERSION=$3
ARCH=$4
WD=$(pwd)
mkdir -p "$TARGET/CONTROL"
grep '^[^(Version|Architecture)]' "$CONTROL" > "$TARGET/CONTROL/control"
grep '^Maintainer' "$CONTROL" 2>&1 >/dev/null || \
echo "Maintainer: LEDE Community <lede-dev@lists.infradead.org>" >> "$TARGET/CONTROL/control"
grep '^Source' "$CONTROL" 2>&1 >/dev/null || {
pkgbase=$(echo "$WD" | sed -e "s|^$TOPDIR/||g")
[ "$pkgbase" = "$WD" ] && src="N/A" || src="$BASE/$pkgbase"
echo "Source: $src" >> "$TARGET/CONTROL/control"
}
echo "Version: $VERSION" >> "$TARGET/CONTROL/control"
echo "Architecture: $ARCH" >> "$TARGET/CONTROL/control"
chmod 644 "$TARGET/CONTROL/control"

2
scripts/md5sum Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
cat "$@" | md5

308
scripts/metadata.pm Normal file
View File

@@ -0,0 +1,308 @@
package metadata;
use base 'Exporter';
use strict;
use warnings;
our @EXPORT = qw(%package %vpackage %srcpackage %category %overrides clear_packages parse_package_metadata parse_target_metadata get_multiline @ignore %usernames %groupnames);
our %package;
our %vpackage;
our %srcpackage;
our %category;
our %overrides;
our @ignore;
our %usernames;
our %groupnames;
our %userids;
our %groupids;
sub get_multiline {
my $fh = shift;
my $prefix = shift;
my $str;
while (<$fh>) {
last if /^@@/;
$str .= (($_ and $prefix) ? $prefix . $_ : $_);
}
return $str ? $str : "";
}
sub confstr($) {
my $conf = shift;
$conf =~ tr#/\.\-/#___#;
return $conf;
}
sub parse_package_metadata_usergroup($$$$$) {
my $makefile = shift;
my $typename = shift;
my $names = shift;
my $ids = shift;
my $spec = shift;
my $name;
my $id;
# the regex for name is taken from is_valid_name() of package shadow
if ($spec =~ /^([a-z_][a-z0-9_-]*\$?)$/) {
$name = $spec;
$id = -1;
} elsif ($spec =~ /^([a-z_][a-z0-9_-]*\$?)=(\d+)$/) {
$name = $1;
$id = $2;
} else {
warn "$makefile: invalid $typename spec $spec\n";
return 0;
}
if ($id =~ /^[1-9]\d*$/) {
if ($id >= 65536) {
warn "$makefile: $typename $name id $id >= 65536";
return 0;
}
if (not exists $ids->{$id}) {
$ids->{$id} = {
name => $name,
makefile => $makefile,
};
} elsif ($ids->{$id}{name} ne $name) {
warn "$makefile: $typename $name id $id is already taken by $ids->{$id}{makefile}\n";
return 0;
}
} elsif ($id != -1) {
warn "$makefile: $typename $name has invalid id $id\n";
return 0;
}
if (not exists $names->{$name}) {
$names->{$name} = {
id => $id,
makefile => $makefile,
};
} elsif ($names->{$name}{id} != $id) {
warn "$makefile: id of $typename $name collides with that defined defined in $names->{$name}{makefile}\n";
return 0;
}
return 1;
}
sub parse_target_metadata($) {
my $file = shift;
my ($target, @target, $profile);
my %target;
my $makefile;
open FILE, "<$file" or do {
warn "Can't open file '$file': $!\n";
return;
};
while (<FILE>) {
chomp;
/^Source-Makefile: \s*((.+\/)([^\/]+)\/Makefile)\s*$/ and $makefile = $1;
/^Target:\s*(.+)\s*$/ and do {
my $name = $1;
$target = {
id => $name,
board => $name,
makefile => $makefile,
boardconf => confstr($name),
conf => confstr($name),
profiles => [],
features => [],
depends => [],
subtargets => []
};
push @target, $target;
$target{$name} = $target;
if ($name =~ /([^\/]+)\/([^\/]+)/) {
push @{$target{$1}->{subtargets}}, $2;
$target->{board} = $1;
$target->{boardconf} = confstr($1);
$target->{subtarget} = 1;
$target->{parent} = $target{$1};
}
};
/^Target-Name:\s*(.+)\s*$/ and $target->{name} = $1;
/^Target-Arch:\s*(.+)\s*$/ and $target->{arch} = $1;
/^Target-Arch-Packages:\s*(.+)\s*$/ and $target->{arch_packages} = $1;
/^Target-Features:\s*(.+)\s*$/ and $target->{features} = [ split(/\s+/, $1) ];
/^Target-Depends:\s*(.+)\s*$/ and $target->{depends} = [ split(/\s+/, $1) ];
/^Target-Description:/ and $target->{desc} = get_multiline(*FILE);
/^Target-Optimization:\s*(.+)\s*$/ and $target->{cflags} = $1;
/^CPU-Type:\s*(.+)\s*$/ and $target->{cputype} = $1;
/^Linux-Version:\s*(.+)\s*$/ and $target->{version} = $1;
/^Linux-Testing-Version:\s*(.+)\s*$/ and $target->{testing_version} = $1;
/^Linux-Release:\s*(.+)\s*$/ and $target->{release} = $1;
/^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1;
/^Default-Subtarget:\s*(.+)\s*$/ and $target->{def_subtarget} = $1;
/^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ];
/^Target-Profile:\s*(.+)\s*$/ and do {
$profile = {
id => $1,
name => $1,
has_image_metadata => 0,
supported_devices => [],
priority => 999,
packages => [],
default => "y if TARGET_ALL_PROFILES"
};
$1 =~ /^DEVICE_/ and $target->{has_devices} = 1;
push @{$target->{profiles}}, $profile;
};
/^Target-Profile-Name:\s*(.+)\s*$/ and $profile->{name} = $1;
/^Target-Profile-hasImageMetadata:\s*(\d+)\s*$/ and $profile->{has_image_metadata} = $1;
/^Target-Profile-SupportedDevices:\s*(.+)\s*$/ and $profile->{supported_devices} = [ split(/\s+/, $1) ];
/^Target-Profile-Priority:\s*(\d+)\s*$/ and do {
$profile->{priority} = $1;
$target->{sort} = 1;
};
/^Target-Profile-Packages:\s*(.*)\s*$/ and $profile->{packages} = [ split(/\s+/, $1) ];
/^Target-Profile-Description:\s*(.*)\s*/ and $profile->{desc} = get_multiline(*FILE);
/^Target-Profile-Default:\s*(.+)\s*$/ and $profile->{default} = $1;
}
close FILE;
foreach my $target (@target) {
if (@{$target->{subtargets}} > 0) {
$target->{profiles} = [];
next;
}
@{$target->{profiles}} > 0 or $target->{profiles} = [
{
id => 'Default',
name => 'Default',
packages => []
}
];
$target->{sort} and @{$target->{profiles}} = sort {
$a->{priority} <=> $b->{priority} or
$a->{name} cmp $b->{name};
} @{$target->{profiles}};
}
return @target;
}
sub clear_packages() {
%package = ();
%vpackage = ();
%srcpackage = ();
%category = ();
%overrides = ();
%usernames = ();
%groupnames = ();
}
sub parse_package_metadata($) {
my $file = shift;
my $pkg;
my $src;
my $override;
my %ignore = map { $_ => 1 } @ignore;
open FILE, "<$file" or do {
warn "Cannot open '$file': $!\n";
return undef;
};
while (<FILE>) {
chomp;
/^Source-Makefile: \s*((?:package\/)?((?:.+\/)?([^\/]+))\/Makefile)\s*$/ and do {
$src = {
makefile => $1,
path => $2,
name => $3,
ignore => $ignore{$3},
packages => [],
buildtypes => [],
builddepends => [],
};
$srcpackage{$3} = $src;
$override = "";
undef $pkg;
};
/^Override: \s*(.+?)\s*$/ and do {
$override = $1;
$overrides{$src->{name}} = 1;
};
next unless $src;
/^Package:\s*(.+?)\s*$/ and do {
$pkg = {};
$pkg->{src} = $src;
$pkg->{name} = $1;
$pkg->{title} = "";
$pkg->{depends} = [];
$pkg->{mdepends} = [];
$pkg->{provides} = [$1];
$pkg->{tristate} = 1;
$pkg->{override} = $override;
$package{$1} = $pkg;
push @{$src->{packages}}, $pkg;
$vpackage{$1} or $vpackage{$1} = [];
unshift @{$vpackage{$1}}, $pkg;
};
/^Build-Depends: \s*(.+)\s*$/ and $src->{builddepends} = [ split /\s+/, $1 ];
/^Build-Depends\/(\w+): \s*(.+)\s*$/ and $src->{"builddepends/$1"} = [ split /\s+/, $2 ];
/^Build-Types:\s*(.+)\s*$/ and $src->{buildtypes} = [ split /\s+/, $1 ];
next unless $pkg;
/^Version: \s*(.+)\s*$/ and $pkg->{version} = $1;
/^ABIVersion: \s*(.+)\s*$/ and $pkg->{abiversion} = $1;
/^Title: \s*(.+)\s*$/ and $pkg->{title} = $1;
/^Menu: \s*(.+)\s*$/ and $pkg->{menu} = $1;
/^Submenu: \s*(.+)\s*$/ and $pkg->{submenu} = $1;
/^Submenu-Depends: \s*(.+)\s*$/ and $pkg->{submenudep} = $1;
/^Source: \s*(.+)\s*$/ and $pkg->{source} = $1;
/^License: \s*(.+)\s*$/ and $pkg->{license} = $1;
/^LicenseFiles: \s*(.+)\s*$/ and $pkg->{licensefiles} = $1;
/^Default: \s*(.+)\s*$/ and $pkg->{default} = $1;
/^Provides: \s*(.+)\s*$/ and do {
my @vpkg = split /\s+/, $1;
@{$pkg->{provides}} = ($pkg->{name}, @vpkg);
foreach my $vpkg (@vpkg) {
next if ($vpkg eq $pkg->{name});
$vpackage{$vpkg} or $vpackage{$vpkg} = [];
push @{$vpackage{$vpkg}}, $pkg;
}
};
/^Menu-Depends: \s*(.+)\s*$/ and $pkg->{mdepends} = [ split /\s+/, $1 ];
/^Depends: \s*(.+)\s*$/ and $pkg->{depends} = [ split /\s+/, $1 ];
/^Conflicts: \s*(.+)\s*$/ and $pkg->{conflicts} = [ split /\s+/, $1 ];
/^Hidden: \s*(.+)\s*$/ and $pkg->{hidden} = 1;
/^Build-Variant: \s*([\w\-]+)\s*/ and $pkg->{variant} = $1;
/^Default-Variant: .*/ and $pkg->{variant_default} = 1;
/^Build-Only: \s*(.+)\s*$/ and $pkg->{buildonly} = 1;
/^Repository:\s*(.+?)\s*$/ and $pkg->{repository} = $1;
/^Category: \s*(.+)\s*$/ and do {
$pkg->{category} = $1;
defined $category{$1} or $category{$1} = {};
defined $category{$1}{$src->{name}} or $category{$1}{$src->{name}} = [];
push @{$category{$1}{$src->{name}}}, $pkg;
};
/^Description: \s*(.*)\s*$/ and $pkg->{description} = "\t\t $1\n". get_multiline(*FILE, "\t\t ");
/^Type: \s*(.+)\s*$/ and do {
$pkg->{type} = [ split /\s+/, $1 ];
undef $pkg->{tristate};
foreach my $type (@{$pkg->{type}}) {
$type =~ /ipkg/ and $pkg->{tristate} = 1;
}
};
/^Config:\s*(.*)\s*$/ and $pkg->{config} = "$1\n".get_multiline(*FILE, "\t");
/^Prereq-Check:/ and $pkg->{prereq} = 1;
/^Require-User:\s*(.*?)\s*$/ and do {
my @ugspecs = split /\s+/, $1;
for my $ugspec (@ugspecs) {
my @ugspec = split /:/, $ugspec, 2;
if ($ugspec[0]) {
parse_package_metadata_usergroup($src->{makefile}, "user", \%usernames, \%userids, $ugspec[0]) or return 0;
}
if ($ugspec[1]) {
parse_package_metadata_usergroup($src->{makefile}, "group", \%groupnames, \%groupids, $ugspec[1]) or return 0;
}
}
};
}
close FILE;
return 1;
}
1;

827
scripts/mkhash.c Normal file
View File

@@ -0,0 +1,827 @@
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* -- MD5 code:
*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*
* -- SHA256 Code:
*
* Copyright 2005 Colin Percival
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <endian.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#define ARRAY_SIZE(_n) (sizeof(_n) / sizeof((_n)[0]))
static void
be32enc(void *buf, uint32_t u)
{
uint8_t *p = buf;
p[0] = ((uint8_t) ((u >> 24) & 0xff));
p[1] = ((uint8_t) ((u >> 16) & 0xff));
p[2] = ((uint8_t) ((u >> 8) & 0xff));
p[3] = ((uint8_t) (u & 0xff));
}
static void
be64enc(void *buf, uint64_t u)
{
uint8_t *p = buf;
be32enc(p, ((uint32_t) (u >> 32)));
be32enc(p + 4, ((uint32_t) (u & 0xffffffffULL)));
}
static uint16_t
be16dec(const void *buf)
{
const uint8_t *p = buf;
return (((uint16_t) p[0]) << 8) | p[1];
}
static uint32_t
be32dec(const void *buf)
{
const uint8_t *p = buf;
return (((uint32_t) be16dec(p)) << 16) | be16dec(p + 2);
}
#define MD5_DIGEST_LENGTH 16
typedef struct MD5_CTX {
uint32_t lo, hi;
uint32_t a, b, c, d;
unsigned char buffer[64];
} MD5_CTX;
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) (((x) ^ (y)) ^ (z))
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them
* in a properly aligned word in host byte order.
*/
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SET(n) \
(*(uint32_t *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
#else
#define SET(n) \
(block[(n)] = \
(uint32_t)ptr[(n) * 4] | \
((uint32_t)ptr[(n) * 4 + 1] << 8) | \
((uint32_t)ptr[(n) * 4 + 2] << 16) | \
((uint32_t)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update
* the bit counters. There are no alignment requirements.
*/
static const void *MD5_body(MD5_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
uint32_t a, b, c, d;
uint32_t saved_a, saved_b, saved_c, saved_d;
#if __BYTE_ORDER != __LITTLE_ENDIAN
uint32_t block[16];
#endif
ptr = (const unsigned char *)data;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
void MD5_begin(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
ctx->c = 0x98badcfe;
ctx->d = 0x10325476;
ctx->lo = 0;
ctx->hi = 0;
}
static void
MD5_hash(const void *data, size_t size, MD5_CTX *ctx)
{
uint32_t saved_lo;
unsigned long used, available;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
available = 64 - used;
if (size < available) {
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
MD5_body(ctx, ctx->buffer, 64);
}
if (size >= 64) {
data = MD5_body(ctx, data, size & ~((size_t) 0x3f));
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
static void
MD5_end(void *resbuf, MD5_CTX *ctx)
{
unsigned char *result = resbuf;
unsigned long used, available;
used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
available = 64 - used;
if (available < 8) {
memset(&ctx->buffer[used], 0, available);
MD5_body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
memset(&ctx->buffer[used], 0, available - 8);
ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24;
MD5_body(ctx, ctx->buffer, 64);
result[0] = ctx->a;
result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24;
result[4] = ctx->b;
result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24;
result[8] = ctx->c;
result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24;
result[12] = ctx->d;
result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24;
memset(ctx, 0, sizeof(*ctx));
}
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
typedef struct SHA256Context {
uint32_t state[8];
uint64_t count;
uint8_t buf[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
#if BYTE_ORDER == BIG_ENDIAN
/* Copy a vector of big-endian uint32_t into a vector of bytes */
#define be32enc_vect(dst, src, len) \
memcpy((void *)dst, (const void *)src, (size_t)len)
/* Copy a vector of bytes into a vector of big-endian uint32_t */
#define be32dec_vect(dst, src, len) \
memcpy((void *)dst, (const void *)src, (size_t)len)
#else /* BYTE_ORDER != BIG_ENDIAN */
/*
* Encode a length len/4 vector of (uint32_t) into a length len vector of
* (unsigned char) in big-endian form. Assumes len is a multiple of 4.
*/
static void
be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
be32enc(dst + i * 4, src[i]);
}
/*
* Decode a big-endian length len vector of (unsigned char) into a length
* len/4 vector of (uint32_t). Assumes len is a multiple of 4.
*/
static void
be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
dst[i] = be32dec(src + i * 4);
}
#endif /* BYTE_ORDER != BIG_ENDIAN */
/* Elementary functions used by SHA256 */
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
#define Maj(x, y, z) ((x & (y | z)) | (y & z))
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
static void
SHA256_Transform(uint32_t * state, const unsigned char block[64])
{
/* SHA256 round constants. */
static const uint32_t K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
uint32_t W[64];
uint32_t S[8];
int i;
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (x >> 3))
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (x >> 10))
/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k) \
h += S1(e) + Ch(e, f, g) + k; \
d += h; \
h += S0(a) + Maj(a, b, c);
/* Adjusted round function for rotating state */
#define RNDr(S, W, i, ii) \
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
S[(66 - i) % 8], S[(67 - i) % 8], \
S[(68 - i) % 8], S[(69 - i) % 8], \
S[(70 - i) % 8], S[(71 - i) % 8], \
W[i + ii] + K[i + ii])
/* Message schedule computation */
#define MSCH(W, ii, i) \
W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii]
/* 1. Prepare the first part of the message schedule W. */
be32dec_vect(W, block, 64);
/* 2. Initialize working variables. */
memcpy(S, state, 32);
/* 3. Mix. */
for (i = 0; i < 64; i += 16) {
RNDr(S, W, 0, i);
RNDr(S, W, 1, i);
RNDr(S, W, 2, i);
RNDr(S, W, 3, i);
RNDr(S, W, 4, i);
RNDr(S, W, 5, i);
RNDr(S, W, 6, i);
RNDr(S, W, 7, i);
RNDr(S, W, 8, i);
RNDr(S, W, 9, i);
RNDr(S, W, 10, i);
RNDr(S, W, 11, i);
RNDr(S, W, 12, i);
RNDr(S, W, 13, i);
RNDr(S, W, 14, i);
RNDr(S, W, 15, i);
if (i == 48)
break;
MSCH(W, 0, i);
MSCH(W, 1, i);
MSCH(W, 2, i);
MSCH(W, 3, i);
MSCH(W, 4, i);
MSCH(W, 5, i);
MSCH(W, 6, i);
MSCH(W, 7, i);
MSCH(W, 8, i);
MSCH(W, 9, i);
MSCH(W, 10, i);
MSCH(W, 11, i);
MSCH(W, 12, i);
MSCH(W, 13, i);
MSCH(W, 14, i);
MSCH(W, 15, i);
}
#undef S0
#undef s0
#undef S1
#undef s1
#undef RND
#undef RNDr
#undef MSCH
/* 4. Mix local working variables into global state */
for (i = 0; i < 8; i++)
state[i] += S[i];
}
static unsigned char PAD[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* Add padding and terminating bit-count. */
static void
SHA256_Pad(SHA256_CTX * ctx)
{
size_t r;
/* Figure out how many bytes we have buffered. */
r = (ctx->count >> 3) & 0x3f;
/* Pad to 56 mod 64, transforming if we finish a block en route. */
if (r < 56) {
/* Pad to 56 mod 64. */
memcpy(&ctx->buf[r], PAD, 56 - r);
} else {
/* Finish the current block and mix. */
memcpy(&ctx->buf[r], PAD, 64 - r);
SHA256_Transform(ctx->state, ctx->buf);
/* The start of the final block is all zeroes. */
memset(&ctx->buf[0], 0, 56);
}
/* Add the terminating bit-count. */
be64enc(&ctx->buf[56], ctx->count);
/* Mix in the final block. */
SHA256_Transform(ctx->state, ctx->buf);
}
/* SHA-256 initialization. Begins a SHA-256 operation. */
static void
SHA256_Init(SHA256_CTX * ctx)
{
/* Zero bits processed so far */
ctx->count = 0;
/* Magic initialization constants */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
/* Add bytes into the hash */
static void
SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len)
{
uint64_t bitlen;
uint32_t r;
const unsigned char *src = in;
/* Number of bytes left in the buffer from previous updates */
r = (ctx->count >> 3) & 0x3f;
/* Convert the length into a number of bits */
bitlen = len << 3;
/* Update number of bits */
ctx->count += bitlen;
/* Handle the case where we don't need to perform any transforms */
if (len < 64 - r) {
memcpy(&ctx->buf[r], src, len);
return;
}
/* Finish the current block */
memcpy(&ctx->buf[r], src, 64 - r);
SHA256_Transform(ctx->state, ctx->buf);
src += 64 - r;
len -= 64 - r;
/* Perform complete blocks */
while (len >= 64) {
SHA256_Transform(ctx->state, src);
src += 64;
len -= 64;
}
/* Copy left over data into buffer */
memcpy(ctx->buf, src, len);
}
/*
* SHA-256 finalization. Pads the input data, exports the hash value,
* and clears the context state.
*/
static void
SHA256_Final(unsigned char digest[static SHA256_DIGEST_LENGTH], SHA256_CTX *ctx)
{
/* Add padding */
SHA256_Pad(ctx);
/* Write the hash */
be32enc_vect(digest, ctx->state, SHA256_DIGEST_LENGTH);
/* Clear the context state */
memset(ctx, 0, sizeof(*ctx));
}
static void *hash_buf(FILE *f, int *len)
{
static char buf[1024];
*len = fread(buf, 1, sizeof(buf), f);
return *len > 0 ? buf : NULL;
}
static char *hash_string(unsigned char *buf, int len)
{
static char str[SHA256_DIGEST_LENGTH * 2 + 1];
int i;
if (len * 2 + 1 > sizeof(str))
return NULL;
for (i = 0; i < len; i++)
sprintf(&str[i * 2], "%02x", buf[i]);
return str;
}
static const char *md5_hash(FILE *f)
{
MD5_CTX ctx;
unsigned char val[MD5_DIGEST_LENGTH];
void *buf;
int len;
MD5_begin(&ctx);
while ((buf = hash_buf(f, &len)) != NULL)
MD5_hash(buf, len, &ctx);
MD5_end(val, &ctx);
return hash_string(val, MD5_DIGEST_LENGTH);
}
static const char *sha256_hash(FILE *f)
{
SHA256_CTX ctx;
unsigned char val[SHA256_DIGEST_LENGTH];
void *buf;
int len;
SHA256_Init(&ctx);
while ((buf = hash_buf(f, &len)) != NULL)
SHA256_Update(&ctx, buf, len);
SHA256_Final(val, &ctx);
return hash_string(val, SHA256_DIGEST_LENGTH);
}
struct hash_type {
const char *name;
const char *(*func)(FILE *f);
int len;
};
struct hash_type types[] = {
{ "md5", md5_hash, MD5_DIGEST_LENGTH },
{ "sha256", sha256_hash, SHA256_DIGEST_LENGTH },
};
static int usage(const char *progname)
{
int i;
fprintf(stderr, "Usage: %s <hash type> [<file>...]\n"
"Supported hash types:", progname);
for (i = 0; i < ARRAY_SIZE(types); i++)
fprintf(stderr, "%s %s", i ? "," : "", types[i].name);
fprintf(stderr, "\n");
return 1;
}
static struct hash_type *get_hash_type(const char *name)
{
int i;
for (i = 0; i < ARRAY_SIZE(types); i++) {
struct hash_type *t = &types[i];
if (!strcmp(t->name, name))
return t;
}
return NULL;
}
static int hash_file(struct hash_type *t, const char *filename, bool add_filename)
{
const char *str;
if (!filename || !strcmp(filename, "-")) {
str = t->func(stdin);
} else {
FILE *f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "Failed to open '%s'\n", filename);
return 1;
}
str = t->func(f);
fclose(f);
}
if (!str) {
fprintf(stderr, "Failed to generate hash\n");
return 1;
}
if (add_filename)
printf("%s %s\n", str, filename ? filename : "-");
else
printf("%s\n", str);
return 0;
}
int main(int argc, char **argv)
{
struct hash_type *t;
const char *progname = argv[0];
int i, ch;
bool add_filename = false;
while ((ch = getopt(argc, argv, "n")) != -1) {
switch (ch) {
case 'n':
add_filename = true;
break;
default:
return usage(progname);
}
}
argc -= optind;
argv += optind;
if (argc < 1)
return usage(progname);
t = get_hash_type(argv[0]);
if (!t)
return usage(progname);
if (argc < 2)
return hash_file(t, NULL, add_filename);
for (i = 0; i < argc - 1; i++)
hash_file(t, argv[1 + i], add_filename);
return 0;
}

59
scripts/mkits-qsdk-ipq-image.sh Executable file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#
# Licensed under the terms of the GNU GPL License version 2 or later.
# Author: Piotr Dymacz <pepe2k@gmail.com>, based on mkits.sh.
#
# Qualcomm SDK (QSDK) sysupgrade compatible images for IPQ40xx, IPQ806x
# and IPQ807x use FIT format together with 'dumpimage' tool from U-Boot
# for verifying and extracting them. Based on 'images' sections names,
# corresponding mtd partitions are flashed.
# This is a simple script for generating FIT images tree source files,
# compatible with the QSDK sysupgrade format. Resulting images can be
# used for initial (factory -> OpenWrt) installation and would work
# both in CLI and GUI. The script is also universal in a way it allows
# to include as many sections as needed.
#
usage() {
echo "Usage: `basename $0` output img0_name img0_file [[img1_name img1_file] ...]"
exit 1
}
# We need at least 3 arguments
[ "$#" -lt 3 ] && usage
# Target output file
OUTPUT="$1"; shift
# Create a default, fully populated DTS file
echo "\
/dts-v1/;
/ {
description = \"OpenWrt factory image\";
#address-cells = <1>;
images {" > ${OUTPUT}
while [ -n "$1" -a -n "$2" ]; do
[ -f "$2" ] || usage
name="$1"; shift
file="$1"; shift
echo \
" ${name} {
description = \"${name}\";
data = /incbin/(\"${file}\");
type = \"Firmware\";
arch = \"ARM\";
compression = \"none\";
hash@1 {
algo = \"crc32\";
};
};" >> ${OUTPUT}
done
echo \
" };
};" >> ${OUTPUT}

118
scripts/mkits.sh Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
#
# Licensed under the terms of the GNU GPL License version 2 or later.
#
# Author: Peter Tyser <ptyser@xes-inc.com>
#
# U-Boot firmware supports the booting of images in the Flattened Image
# Tree (FIT) format. The FIT format uses a device tree structure to
# describe a kernel image, device tree blob, ramdisk, etc. This script
# creates an Image Tree Source (.its file) which can be passed to the
# 'mkimage' utility to generate an Image Tree Blob (.itb file). The .itb
# file can then be booted by U-Boot (or other bootloaders which support
# FIT images). See doc/uImage.FIT/howto.txt in U-Boot source code for
# additional information on FIT images.
#
usage() {
echo "Usage: `basename $0` -A arch -C comp -a addr -e entry" \
"-v version -k kernel [-D name -d dtb] -o its_file"
echo -e "\t-A ==> set architecture to 'arch'"
echo -e "\t-C ==> set compression type 'comp'"
echo -e "\t-c ==> set config name 'config'"
echo -e "\t-a ==> set load address to 'addr' (hex)"
echo -e "\t-e ==> set entry point to 'entry' (hex)"
echo -e "\t-v ==> set kernel version to 'version'"
echo -e "\t-k ==> include kernel image 'kernel'"
echo -e "\t-D ==> human friendly Device Tree Blob 'name'"
echo -e "\t-d ==> include Device Tree Blob 'dtb'"
echo -e "\t-o ==> create output file 'its_file'"
exit 1
}
while getopts ":A:a:c:C:D:d:e:k:o:v:" OPTION
do
case $OPTION in
A ) ARCH=$OPTARG;;
a ) LOAD_ADDR=$OPTARG;;
c ) CONFIG=$OPTARG;;
C ) COMPRESS=$OPTARG;;
D ) DEVICE=$OPTARG;;
d ) DTB=$OPTARG;;
e ) ENTRY_ADDR=$OPTARG;;
k ) KERNEL=$OPTARG;;
o ) OUTPUT=$OPTARG;;
v ) VERSION=$OPTARG;;
* ) echo "Invalid option passed to '$0' (options:$@)"
usage;;
esac
done
# Make sure user entered all required parameters
if [ -z "${ARCH}" ] || [ -z "${COMPRESS}" ] || [ -z "${LOAD_ADDR}" ] || \
[ -z "${ENTRY_ADDR}" ] || [ -z "${VERSION}" ] || [ -z "${KERNEL}" ] || \
[ -z "${OUTPUT}" ] || [ -z "${CONFIG}" ]; then
usage
fi
ARCH_UPPER=`echo $ARCH | tr '[:lower:]' '[:upper:]'`
# Conditionally create fdt information
if [ -n "${DTB}" ]; then
FDT_NODE="
fdt@1 {
description = \"${ARCH_UPPER} OpenWrt ${DEVICE} device tree blob\";
data = /incbin/(\"${DTB}\");
type = \"flat_dt\";
arch = \"${ARCH}\";
compression = \"none\";
hash@1 {
algo = \"crc32\";
};
hash@2 {
algo = \"sha1\";
};
};
"
FDT_PROP="fdt = \"fdt@1\";"
fi
# Create a default, fully populated DTS file
DATA="/dts-v1/;
/ {
description = \"${ARCH_UPPER} OpenWrt FIT (Flattened Image Tree)\";
#address-cells = <1>;
images {
kernel@1 {
description = \"${ARCH_UPPER} OpenWrt Linux-${VERSION}\";
data = /incbin/(\"${KERNEL}\");
type = \"kernel\";
arch = \"${ARCH}\";
os = \"linux\";
compression = \"${COMPRESS}\";
load = <${LOAD_ADDR}>;
entry = <${ENTRY_ADDR}>;
hash@1 {
algo = \"crc32\";
};
hash@2 {
algo = \"sha1\";
};
};
${FDT_NODE}
};
configurations {
default = \"${CONFIG}\";
${CONFIG} {
description = \"OpenWrt\";
kernel = \"kernel@1\";
${FDT_PROP}
};
};
};"
# Write .its file to disk
echo "$DATA" > ${OUTPUT}

99
scripts/om-fwupgradecfg-gen.sh Executable file
View File

@@ -0,0 +1,99 @@
#!/bin/sh
#
# Copyright (C) 2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
usage() {
echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62> <out file path> <kernel path> <rootfs path>"
rm -f $CFG_OUT
exit 1
}
[ "$#" -lt 4 ] && usage
CE_TYPE=$1
CFG_OUT=$2
KERNEL_PATH=$3
ROOTFS_PATH=$4
case $CE_TYPE in
OM2P)
MAX_PART_SIZE=7168
KERNEL_FLASH_ADDR=0x1c0000
FLASH_BS=262144
MD5_SKIP_BLOCKS=4
SIZE_FACTOR=1
SIZE_FORMAT="%d"
;;
OM5P|OM5PAC|MR600|MR900|MR1750|A60)
MAX_PART_SIZE=7808
KERNEL_FLASH_ADDR=0xb0000
FLASH_BS=65536
MD5_SKIP_BLOCKS=4
SIZE_FACTOR=1
SIZE_FORMAT="%d"
;;
A42)
MAX_PART_SIZE=15616
KERNEL_FLASH_ADDR=0x180000
FLASH_BS=65536
MD5_SKIP_BLOCKS=4
SIZE_FACTOR=1024
SIZE_FORMAT="0x%08x"
;;
A62)
MAX_PART_SIZE=15552
KERNEL_FLASH_ADDR=0x1a0000
FLASH_BS=65536
MD5_SKIP_BLOCKS=4
SIZE_FACTOR=1024
SIZE_FORMAT="0x%08x"
;;
*)
echo "Error - unsupported ce type: $CE_TYPE"
exit 1
;;
esac
CHECK_BS=65536
KERNEL_SIZE=$(stat -c%s "$KERNEL_PATH")
KERNEL_MD5=$(mkhash md5 $KERNEL_PATH)
KERNEL_SHA256=$(mkhash sha256 $KERNEL_PATH)
KERNEL_PART_SIZE_KB=$(size=$(($KERNEL_SIZE / $FLASH_BS)); [ $(($size * $FLASH_BS)) -lt $KERNEL_SIZE ] && size=$(($size + 1)); echo $(($size * $FLASH_BS / 1024)))
KERNEL_PART_SIZE=$(printf $SIZE_FORMAT $(($KERNEL_PART_SIZE_KB * $SIZE_FACTOR)))
ROOTFS_FLASH_ADDR=$(addr=$(($KERNEL_FLASH_ADDR + ($KERNEL_PART_SIZE_KB * 1024))); printf "0x%x" $addr)
ROOTFS_SIZE=$(stat -c%s "$ROOTFS_PATH")
ROOTFS_CHECK_BLOCKS=$((($ROOTFS_SIZE / $CHECK_BS) - $MD5_SKIP_BLOCKS))
ROOTFS_MD5=$(dd if=$ROOTFS_PATH bs=$CHECK_BS count=$ROOTFS_CHECK_BLOCKS 2>&- | mkhash md5)
ROOTFS_MD5_FULL=$(mkhash md5 $ROOTFS_PATH)
ROOTFS_SHA256_FULL=$(mkhash sha256 $ROOTFS_PATH)
ROOTFS_CHECK_SIZE=$(printf '0x%x' $(($ROOTFS_CHECK_BLOCKS * $CHECK_BS)))
ROOTFS_PART_SIZE_KB=$(($MAX_PART_SIZE - $KERNEL_PART_SIZE_KB))
ROOTFS_PART_SIZE=$(printf $SIZE_FORMAT $(($ROOTFS_PART_SIZE_KB * $SIZE_FACTOR)))
cat << EOF > $CFG_OUT
[vmlinux]
filename=kernel
md5sum=$KERNEL_MD5
filemd5sum=$KERNEL_MD5
filesha256sum=$KERNEL_SHA256
flashaddr=$KERNEL_FLASH_ADDR
checksize=0x0
cmd_success=setenv bootseq 1,2; setenv kernel_size_1 $KERNEL_PART_SIZE; saveenv
cmd_fail=reset
[rootfs]
filename=rootfs
md5sum=$ROOTFS_MD5
filemd5sum=$ROOTFS_MD5_FULL
filesha256sum=$ROOTFS_SHA256_FULL
flashaddr=$ROOTFS_FLASH_ADDR
checksize=$ROOTFS_CHECK_SIZE
cmd_success=setenv bootseq 1,2; setenv kernel_size_1 $KERNEL_PART_SIZE; setenv rootfs_size_1 $ROOTFS_PART_SIZE; saveenv
cmd_fail=reset
EOF

634
scripts/package-metadata.pl Executable file
View File

@@ -0,0 +1,634 @@
#!/usr/bin/env perl
use FindBin;
use lib "$FindBin::Bin";
use strict;
use metadata;
use Getopt::Long;
my %board;
sub version_to_num($) {
my $str = shift;
my $num = 0;
if (defined($str) && $str =~ /^\d+(?:\.\d+)+$/)
{
my @n = (split(/\./, $str), 0, 0, 0, 0);
$num = ($n[0] << 24) | ($n[1] << 16) | ($n[2] << 8) | $n[3];
}
return $num;
}
sub version_filter_list(@) {
my $cmpver = version_to_num(shift @_);
my @items;
foreach my $item (@_)
{
if ($item =~ s/@(lt|le|gt|ge|eq|ne)(\d+(?:\.\d+)+)\b//)
{
my $op = $1;
my $symver = version_to_num($2);
if ($symver > 0 && $cmpver > 0)
{
next unless (($op eq 'lt' && $cmpver < $symver) ||
($op eq 'le' && $cmpver <= $symver) ||
($op eq 'gt' && $cmpver > $symver) ||
($op eq 'ge' && $cmpver >= $symver) ||
($op eq 'eq' && $cmpver == $symver) ||
($op eq 'ne' && $cmpver != $symver));
}
}
push @items, $item;
}
return @items;
}
sub gen_kconfig_overrides() {
my %config;
my %kconfig;
my $package;
my $pkginfo = shift @ARGV;
my $cfgfile = shift @ARGV;
my $patchver = shift @ARGV;
# parameter 2: build system config
open FILE, "<$cfgfile" or return;
while (<FILE>) {
/^(CONFIG_.+?)=(.+)$/ and $config{$1} = 1;
}
close FILE;
# parameter 1: package metadata
open FILE, "<$pkginfo" or return;
while (<FILE>) {
/^Package:\s*(.+?)\s*$/ and $package = $1;
/^Kernel-Config:\s*(.+?)\s*$/ and do {
my @config = split /\s+/, $1;
foreach my $config (version_filter_list($patchver, @config)) {
my $val = 'm';
my $override;
if ($config =~ /^(.+?)=(.+)$/) {
$config = $1;
$override = 1;
$val = $2;
}
if ($config{"CONFIG_PACKAGE_$package"} and ($config ne 'n')) {
next if $kconfig{$config} eq 'y';
$kconfig{$config} = $val;
} elsif (!$override) {
$kconfig{$config} or $kconfig{$config} = 'n';
}
}
};
};
close FILE;
foreach my $kconfig (sort keys %kconfig) {
if ($kconfig{$kconfig} eq 'n') {
print "# $kconfig is not set\n";
} else {
print "$kconfig=$kconfig{$kconfig}\n";
}
}
}
my %dep_check;
sub __find_package_dep($$) {
my $pkg = shift;
my $name = shift;
my $deps = $pkg->{depends};
return 0 unless defined $deps;
foreach my $vpkg (@{$deps}) {
foreach my $dep (@{$vpackage{$vpkg}}) {
next if $dep_check{$dep->{name}};
$dep_check{$dep->{name}} = 1;
return 1 if $dep->{name} eq $name;
return 1 if (__find_package_dep($dep, $name) == 1);
}
}
return 0;
}
# wrapper to avoid infinite recursion
sub find_package_dep($$) {
my $pkg = shift;
my $name = shift;
%dep_check = ();
return __find_package_dep($pkg, $name);
}
sub package_depends($$) {
my $a = shift;
my $b = shift;
my $ret;
return 0 if ($a->{submenu} ne $b->{submenu});
if (find_package_dep($a, $b->{name}) == 1) {
$ret = 1;
} elsif (find_package_dep($b, $a->{name}) == 1) {
$ret = -1;
} else {
return 0;
}
return $ret;
}
sub mconf_depends {
my $pkgname = shift;
my $depends = shift;
my $only_dep = shift;
my $res;
my $dep = shift;
my $seen = shift;
my $parent_condition = shift;
$dep or $dep = {};
$seen or $seen = {};
my @t_depends;
$depends or return;
my @depends = @$depends;
foreach my $depend (@depends) {
my $m = "depends on";
my $flags = "";
$depend =~ s/^([@\+]+)// and $flags = $1;
my $condition = $parent_condition;
next if $condition eq $depend;
next if $seen->{"$parent_condition:$depend"};
next if $seen->{":$depend"};
$seen->{"$parent_condition:$depend"} = 1;
if ($depend =~ /^(.+):(.+)$/) {
if ($1 ne "PACKAGE_$pkgname") {
if ($condition) {
$condition = "$condition && $1";
} else {
$condition = $1;
}
}
$depend = $2;
}
if ($flags =~ /\+/) {
my $vdep = $vpackage{$depend};
if ($vdep) {
my @vdeps;
foreach my $v (@$vdep) {
next if $v->{buildonly};
if ($v->{variant_default}) {
unshift @vdeps, $v->{name};
} else {
push @vdeps, $v->{name};
}
}
$depend = shift @vdeps;
if (@vdeps > 1) {
$condition = ($condition ? "$condition && " : '') . join("&&", map { "PACKAGE_$_<PACKAGE_$pkgname" } @vdeps);
} elsif (@vdeps > 0) {
$condition = ($condition ? "$condition && " : '') . "PACKAGE_${vdeps[0]}<PACKAGE_$pkgname";
}
}
# Menuconfig will not treat 'select FOO' as a real dependency
# thus if FOO depends on other config options, these dependencies
# will not be checked. To fix this, we simply emit all of FOO's
# depends here as well.
$package{$depend} and push @t_depends, [ $package{$depend}->{depends}, $condition ];
$m = "select";
next if $only_dep;
$flags =~ /@/ or $depend = "PACKAGE_$depend";
} else {
my $vdep = $vpackage{$depend};
if ($vdep && @$vdep > 0) {
$depend = join("||", map { "PACKAGE_".$_->{name} } @$vdep);
} else {
$flags =~ /@/ or $depend = "PACKAGE_$depend";
}
}
if ($condition) {
if ($m =~ /select/) {
next if $depend eq $condition;
$depend = "$depend if $condition";
} else {
next if $dep->{"$depend if $condition"};
$depend = "!($condition) || $depend" unless $dep->{$condition} eq 'select';
}
}
$dep->{$depend} =~ /select/ or $dep->{$depend} = $m;
}
foreach my $tdep (@t_depends) {
mconf_depends($pkgname, $tdep->[0], 1, $dep, $seen, $tdep->[1]);
}
foreach my $depend (keys %$dep) {
my $m = $dep->{$depend};
$res .= "\t\t$m $depend\n";
}
return $res;
}
sub mconf_conflicts {
my $pkgname = shift;
my $depends = shift;
my $res = "";
foreach my $depend (@$depends) {
next unless $package{$depend};
$res .= "\t\tdepends on m || (PACKAGE_$depend != y)\n";
}
return $res;
}
sub print_package_config_category($) {
my $cat = shift;
my %menus;
my %menu_dep;
return unless $category{$cat};
print "menu \"$cat\"\n\n";
my %spkg = %{$category{$cat}};
foreach my $spkg (sort {uc($a) cmp uc($b)} keys %spkg) {
foreach my $pkg (@{$spkg{$spkg}}) {
next if $pkg->{buildonly};
my $menu = $pkg->{submenu};
if ($menu) {
$menu_dep{$menu} or $menu_dep{$menu} = $pkg->{submenudep};
} else {
$menu = 'undef';
}
$menus{$menu} or $menus{$menu} = [];
push @{$menus{$menu}}, $pkg;
}
}
my @menus = sort {
($a eq 'undef' ? 1 : 0) or
($b eq 'undef' ? -1 : 0) or
($a cmp $b)
} keys %menus;
foreach my $menu (@menus) {
my @pkgs = sort {
package_depends($a, $b) or
($a->{name} cmp $b->{name})
} @{$menus{$menu}};
if ($menu ne 'undef') {
$menu_dep{$menu} and print "if $menu_dep{$menu}\n";
print "menu \"$menu\"\n";
}
foreach my $pkg (@pkgs) {
next if $pkg->{src}{ignore};
my $title = $pkg->{name};
my $c = (72 - length($pkg->{name}) - length($pkg->{title}));
if ($c > 0) {
$title .= ("." x $c). " ". $pkg->{title};
}
$title = "\"$title\"";
print "\t";
$pkg->{menu} and print "menu";
print "config PACKAGE_".$pkg->{name}."\n";
$pkg->{hidden} and $title = "";
print "\t\t".($pkg->{tristate} ? 'tristate' : 'bool')." $title\n";
print "\t\tdefault y if DEFAULT_".$pkg->{name}."\n";
unless ($pkg->{hidden}) {
my @def = ("ALL");
if (!exists($pkg->{repository})) {
push @def, "ALL_NONSHARED";
}
if ($pkg->{name} =~ /^kmod-/) {
push @def, "ALL_KMODS";
}
$pkg->{default} ||= "m if " . join("||", @def);
}
if ($pkg->{default}) {
foreach my $default (split /\s*,\s*/, $pkg->{default}) {
print "\t\tdefault $default\n";
}
}
print mconf_depends($pkg->{name}, $pkg->{depends}, 0);
print mconf_depends($pkg->{name}, $pkg->{mdepends}, 0);
print mconf_conflicts($pkg->{name}, $pkg->{conflicts});
print "\t\thelp\n";
print $pkg->{description};
print "\n";
$pkg->{config} and print $pkg->{config}."\n";
}
if ($menu ne 'undef') {
print "endmenu\n";
$menu_dep{$menu} and print "endif\n";
}
}
print "endmenu\n\n";
undef $category{$cat};
}
sub print_package_overrides() {
keys %overrides > 0 or return;
print "\tconfig OVERRIDE_PKGS\n";
print "\t\tstring\n";
print "\t\tdefault \"".join(" ", sort keys %overrides)."\"\n\n";
}
sub gen_package_config() {
parse_package_metadata($ARGV[0]) or exit 1;
print "menuconfig IMAGEOPT\n\tbool \"Image configuration\"\n\tdefault n\n";
print "source \"package/*/image-config.in\"\n";
if (scalar glob "package/feeds/*/*/image-config.in") {
print "source \"package/feeds/*/*/image-config.in\"\n";
}
print_package_config_category 'Base system';
foreach my $cat (sort {uc($a) cmp uc($b)} keys %category) {
print_package_config_category $cat;
}
print_package_overrides();
}
sub and_condition($) {
my $condition = shift;
my @spl_and = split('\&\&', $condition);
if (@spl_and == 1) {
return "\$(CONFIG_$spl_and[0])";
}
return "\$(and " . join (',', map("\$(CONFIG_$_)", @spl_and)) . ")";
}
sub gen_condition ($) {
my $condition = shift;
# remove '!()', just as include/package-ipkg.mk does
$condition =~ s/[()!]//g;
return join("", map(and_condition($_), split('\|\|', $condition)));
}
sub get_conditional_dep($$) {
my $condition = shift;
my $depstr = shift;
if ($condition) {
if ($condition =~ /^!(.+)/) {
return "\$(if " . gen_condition($1) . ",,$depstr)";
} else {
return "\$(if " . gen_condition($condition) . ",$depstr)";
}
} else {
return $depstr;
}
}
sub gen_package_mk() {
my $line;
parse_package_metadata($ARGV[0]) or exit 1;
foreach my $srcname (sort {uc($a) cmp uc($b)} keys %srcpackage) {
my $src = $srcpackage{$srcname};
my $variant_default;
my %deplines = ('' => {});
foreach my $pkg (@{$src->{packages}}) {
foreach my $dep (@{$pkg->{depends}}) {
next if ($dep =~ /@/);
my $condition;
$dep =~ s/\+//g;
if ($dep =~ /^(.+):(.+)/) {
$condition = $1;
$dep = $2;
}
my $vpkg_dep = $vpackage{$dep};
unless (defined $vpkg_dep) {
warn sprintf "WARNING: Makefile '%s' has a dependency on '%s', which does not exist\n",
$src->{makefile}, $dep;
next;
}
# Filter out self-depends
my @vdeps = grep { $srcname ne $_->{src}{name} } @{$vpkg_dep};
foreach my $vdep (@vdeps) {
my $depstr = sprintf '$(curdir)/%s/compile', $vdep->{src}{path};
if (@vdeps > 1) {
$depstr = sprintf '$(if $(CONFIG_PACKAGE_%s),%s)', $vdep->{name}, $depstr;
}
my $depline = get_conditional_dep($condition, $depstr);
if ($depline) {
$deplines{''}{$depline}++;
}
}
}
my $config = '';
$config = sprintf '$(CONFIG_PACKAGE_%s)', $pkg->{name} unless $pkg->{buildonly};
$pkg->{prereq} and printf "prereq-%s += %s\n", $config, $src->{path};
next if $pkg->{buildonly};
printf "package-%s += %s\n", $config, $src->{path};
if ($pkg->{variant}) {
if (!defined($variant_default) or $pkg->{variant_default}) {
$variant_default = $pkg->{variant};
}
printf "\$(curdir)/%s/variants += \$(if %s,%s)\n", $src->{path}, $config, $pkg->{variant};
}
}
if (defined($variant_default)) {
printf "\$(curdir)/%s/default-variant := %s\n", $src->{path}, $variant_default;
}
unless (grep {!$_->{buildonly}} @{$src->{packages}}) {
printf "package- += %s\n", $src->{path};
}
if (@{$src->{buildtypes}} > 0) {
printf "buildtypes-%s = %s\n", $src->{path}, join(' ', @{$src->{buildtypes}});
}
foreach my $type ('', @{$src->{buildtypes}}) {
my $suffix = '';
$suffix = "/$type" if $type;
next unless $src->{"builddepends$suffix"};
defined $deplines{$suffix} or $deplines{$suffix} = {};
foreach my $dep (@{$src->{"builddepends$suffix"}}) {
my $depsuffix = "";
my $deptype = "";
my $condition;
if ($dep =~ /^(.+):(.+)/) {
$condition = $1;
$dep = $2;
}
if ($dep =~ /^(.+)\/(.+)/) {
$dep = $1;
$deptype = $2;
$depsuffix = "/$2";
}
next if $srcname.$suffix eq $dep.$depsuffix;
my $src_dep = $srcpackage{$dep};
unless (defined($src_dep) && (!$deptype || grep { $_ eq $deptype } @{$src_dep->{buildtypes}})) {
warn sprintf "WARNING: Makefile '%s' has a build dependency on '%s', which does not exist\n",
$src->{makefile}, $dep.$depsuffix;
next;
}
my $depstr = sprintf '$(curdir)/%s/compile', $src_dep->{path}.$depsuffix;
my $depline = get_conditional_dep($condition, $depstr);
if ($depline) {
$deplines{$suffix}{$depline}++;
}
}
}
foreach my $suffix (sort keys %deplines) {
my $depline = join(" ", sort keys %{$deplines{$suffix}});
if ($depline) {
$line .= sprintf "\$(curdir)/%s/compile += %s\n", $src->{path}.$suffix, $depline;
}
}
}
if ($line ne "") {
print "\n$line";
}
}
sub gen_package_source() {
parse_package_metadata($ARGV[0]) or exit 1;
foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
my $pkg = $package{$name};
if ($pkg->{name} && $pkg->{source}) {
print "$pkg->{name}: ";
print "$pkg->{source}\n";
}
}
}
sub gen_package_auxiliary() {
parse_package_metadata($ARGV[0]) or exit 1;
foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
my $pkg = $package{$name};
if ($pkg->{name} && $pkg->{repository}) {
print "Package/$name/subdir = $pkg->{repository}\n";
}
if ($pkg->{name} && defined($pkg->{abiversion}) && length($pkg->{abiversion})) {
my $abiv;
if ($pkg->{abiversion} =~ m!^(\d{4})-(\d{2})-(\d{2})-[0-9a-f]{7,40}$!) {
print STDERR "WARNING: Reducing ABI version '$pkg->{abiversion}' of package '$name' to '$1$2$3'\n";
$abiv = "$1$2$3";
}
else {
$abiv = $pkg->{abiversion};
}
foreach my $n (@{$pkg->{provides}}) {
print "Package/$n/abiversion = $abiv\n";
}
}
my %depends;
foreach my $dep (@{$pkg->{depends} || []}) {
if ($dep =~ m!^\+?(?:[^:]+:)?([^@]+)$!) {
$depends{$1}++;
}
}
my @depends = sort keys %depends;
if (@depends > 0) {
foreach my $n (@{$pkg->{provides}}) {
print "Package/$n/depends = @depends\n";
}
}
}
}
sub gen_package_license($) {
my $level = shift;
parse_package_metadata($ARGV[0]) or exit 1;
foreach my $name (sort {uc($a) cmp uc($b)} keys %package) {
my $pkg = $package{$name};
if ($pkg->{name}) {
if ($pkg->{license}) {
print "$pkg->{name}: ";
print "$pkg->{license}\n";
if ($pkg->{licensefiles} && $level == 0) {
print "\tFiles: $pkg->{licensefiles}\n";
}
} else {
if ($level == 1) {
print "$pkg->{name}: Missing license! ";
print "Please fix $pkg->{src}{makefile}\n";
}
}
}
}
}
sub gen_version_filtered_list() {
foreach my $item (version_filter_list(@ARGV)) {
print "$item\n";
}
}
sub gen_usergroup_list() {
parse_package_metadata($ARGV[0]) or exit 1;
for my $name (keys %usernames) {
print "user $name $usernames{$name}{id} $usernames{$name}{makefile}\n";
}
for my $name (keys %groupnames) {
print "group $name $groupnames{$name}{id} $groupnames{$name}{makefile}\n";
}
}
sub parse_command() {
GetOptions("ignore=s", \@ignore);
my $cmd = shift @ARGV;
for ($cmd) {
/^mk$/ and return gen_package_mk();
/^config$/ and return gen_package_config();
/^kconfig/ and return gen_kconfig_overrides();
/^source$/ and return gen_package_source();
/^pkgaux$/ and return gen_package_auxiliary();
/^license$/ and return gen_package_license(0);
/^licensefull$/ and return gen_package_license(1);
/^usergroup$/ and return gen_usergroup_list();
/^version_filter$/ and return gen_version_filtered_list();
}
die <<EOF
Available Commands:
$0 mk [file] Package metadata in makefile format
$0 config [file] Package metadata in Kconfig format
$0 kconfig [file] [config] [patchver] Kernel config overrides
$0 source [file] Package source file information
$0 pkgaux [file] Package auxiliary variables in makefile format
$0 license [file] Package license information
$0 licensefull [file] Package license information (full list)
$0 usergroup [file] Package usergroup allocation list
$0 version_filter [patchver] [list...] Filter list of version tagged strings
Options:
--ignore <name> Ignore the source package <name>
EOF
}
parse_command();

100
scripts/pad_image Executable file
View File

@@ -0,0 +1,100 @@
#!/usr/bin/env bash
function usage {
echo "Usage: prepare_image image_type kernel_image rootfs_image header_size"
echo "Padd root and kernel image to the correct size and append the jffs2 start marker as needed"
exit 1
}
function pad_file {
echo "Padding $1 to size $2"
dd if=$1 of=$1.paddingtempfile bs=$2 count=1 conv=sync &> /dev/null
mv $1.paddingtempfile $1
}
#filesize filestart padding
function calc_pad {
[ $((($1 + $2) & ($3 - 1))) == 0 ] && {
echo $1
return 0
}
echo $(((($1 + $2) | ($3 - 1)) + 1 - $2))
}
function prep_squash {
echo "kernel_size: $kernel_size"
echo "header_size: $header_size"
kernel_pad_size=$(calc_pad $kernel_size $header_size 32)
kernel_end=$(($header_size + $kernel_pad_size))
pad_file $kernel_image $kernel_pad_size
#4k
rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 4096)
pad_file $rootfs_image $rootfs_pad_size
echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
#8k
rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 8192)
[ $rootfs_pad_size == rootfs_old_padsize ] || {
pad_file $rootfs_image $rootfs_pad_size
rootfs_old_padsize=$rootfs_pad_size
echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
}
#64k
rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 65536)
[ $rootfs_pad_size == rootfs_old_padsize ] || {
pad_file $rootfs_image $rootfs_pad_size
rootfs_old_padsize=$rootfs_pad_size
echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
}
#128k
rootfs_pad_size=$(calc_pad $rootfs_size $kernel_end 131072)
[ $rootfs_pad_size == rootfs_old_padsize ] || {
pad_file $rootfs_image $rootfs_pad_size
rootfs_old_padsize=$rootfs_pad_size
echo -ne '\xde\xad\xc0\xde' >> $rootfs_image
}
}
function prep_jffs2 {
kernel_pad_size=$(calc_pad $kernel_size $header_size $1)
pad_file $kernel_image $kernel_pad_size
}
image_type=$1
kernel_image=$2
rootfs_image=$3
header_size=$4
if [ -z "$image_type" ] || [ -z "$rootfs_image" ] || [ -z "$kernel_image" ] || [ -z "$header_size" ]; then
usage
fi
if [ ! -e "$rootfs_image" ] || [ -z "$kernel_image" ]; then
echo "input file not found"
exit 1
fi
kernel_size=$(stat -c "%s" "$kernel_image")
rootfs_size=$(stat -c "%s" "$rootfs_image")
if [ $kernel_size == 0 ] || [ $rootfs_size == 0 ]; then
echo "kernel or rootfs empty"
exit 1
fi
case $image_type in
squashfs )
prep_squash ;;
jffs2-64k )
prep_jffs2 65536 ;;
jffs2-128k )
prep_jffs2 131072 ;;
* )
echo "Unknown image type"
exit 1 ;;
esac

54
scripts/patch-kernel.sh Executable file
View File

@@ -0,0 +1,54 @@
#! /bin/sh
# A little script I whipped up to make it easy to
# patch source trees and have sane error handling
# -Erik
#
# (c) 2002 Erik Andersen <andersen@codepoet.org>
# Set directories from arguments, or use defaults.
targetdir=${1-.}
patchdir=${2-../kernel-patches}
patchpattern=${3-*}
if [ ! -d "${targetdir}" ] ; then
echo "Aborting. '${targetdir}' is not a directory."
exit 1
fi
if [ ! -d "${patchdir}" ] ; then
echo "Aborting. '${patchdir}' is not a directory."
exit 1
fi
for i in ${patchdir}/${patchpattern} ; do
case "$i" in
*.gz)
type="gzip"; uncomp="gunzip -dc"; ;;
*.bz)
type="bzip"; uncomp="bunzip -dc"; ;;
*.bz2)
type="bzip2"; uncomp="bunzip2 -dc"; ;;
*.zip)
type="zip"; uncomp="unzip -d"; ;;
*.Z)
type="compress"; uncomp="uncompress -c"; ;;
*)
type="plaintext"; uncomp="cat"; ;;
esac
[ -d "${i}" ] && echo "Ignoring subdirectory ${i}" && continue
echo ""
echo "Applying ${i} using ${type}: "
${uncomp} ${i} | ${PATCH:-patch} -f -p1 -d ${targetdir}
if [ $? != 0 ] ; then
echo "Patch failed! Please fix $i!"
exit 1
fi
done
# Check for rejects...
if [ "`find $targetdir/ '(' -name '*.rej' -o -name '.*.rej' ')' -print`" ] ; then
echo "Aborting. Reject files found."
exit 1
fi
# Remove backup files
find $targetdir/ '(' -name '*.orig' -o -name '.*.orig' ')' -exec rm -f {} \;

90
scripts/patch-specs.sh Executable file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env bash
DIR="$1"
if [ -d "$DIR" ]; then
DIR="$(cd "$DIR"; pwd)"
else
echo "Usage: $0 toolchain-dir"
exit 1
fi
echo -n "Locating cpp ... "
for bin in bin usr/bin usr/local/bin; do
for cmd in "$DIR/$bin/"*-cpp; do
if [ -x "$cmd" ]; then
echo "$cmd"
CPP="$cmd"
break
fi
done
done
if [ ! -x "$CPP" ]; then
echo "Can't locate a cpp executable in '$DIR' !"
exit 1
fi
patch_specs() {
local found=0
for lib in $(STAGING_DIR="$DIR" "$CPP" -x c -v /dev/null 2>&1 | sed -ne 's#:# #g; s#^LIBRARY_PATH=##p'); do
if [ -d "$lib" ]; then
grep -qs "STAGING_DIR" "$lib/specs" && rm -f "$lib/specs"
if [ $found -lt 1 ]; then
echo -n "Patching specs ... "
STAGING_DIR="$DIR" "$CPP" -dumpspecs | awk '
mode ~ "link" {
sub("%{L.}", "%{L*} -L %:getenv(STAGING_DIR /usr/lib) -rpath-link %:getenv(STAGING_DIR /usr/lib)")
}
mode ~ "cpp" {
$0 = $0 " -idirafter %:getenv(STAGING_DIR /usr/include)"
}
{
print $0
mode = ""
}
/^\*cpp:/ {
mode = "cpp"
}
/^\*link.*:/ {
mode = "link"
}
' > "$lib/specs"
echo "ok"
found=1
fi
fi
done
[ $found -gt 0 ]
return $?
}
VERSION="$(STAGING_DIR="$DIR" "$CPP" --version | sed -ne 's/^.* (.*) //; s/ .*$//; 1p')"
VERSION="${VERSION:-unknown}"
case "${VERSION##* }" in
2.*|3.*|4.0.*|4.1.*|4.2.*)
echo "The compiler version does not support getenv() in spec files."
echo -n "Wrapping binaries instead ... "
if "${0%/*}/ext-toolchain.sh" --toolchain "$DIR" --wrap "${CPP%/*}"; then
echo "ok"
exit 0
else
echo "failed"
exit $?
fi
;;
*)
if patch_specs; then
echo "Toolchain successfully patched."
exit 0
else
echo "Failed to locate library directory!"
exit 1
fi
;;
esac

11
scripts/portable_date.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
case $(uname) in
NetBSD|OpenBSD|DragonFly|FreeBSD|Darwin)
date -j -f "%Y-%m-%d %H:%M:%S %z" "$1" "$2" 2>/dev/null
;;
*)
date -d "$1" "$2"
esac
exit $?

340
scripts/qemustart Executable file
View File

@@ -0,0 +1,340 @@
#!/usr/bin/env bash
SELF="$0"
# Linux bridge for connecting lan and wan network of guest machines
BR_LAN="${BR_LAN:-br-lan}"
BR_WAN="${BR_WAN:-br-wan}"
# Host network interface providing internet access for guest machines
IF_INET="${IF_INET:-eth0}"
# qemu-bridge-helper does two things here
#
# - create tap interface
# - add the tap interface to bridge
#
# as such it requires CAP_NET_ADMIN to do its job. It will be convenient to
# have it as a root setuid program. Be aware of the security risks implied
#
# the helper has an acl list which defaults to deny all bridge. we need to add
# $BR_LAN and $BR_WAN to its allow list
#
# # sudo vim /etc/qemu/bridge.conf
# allow br-lan
# allow br-wan
#
# Other allowed directives can be 'allow all', 'deny all', 'include xxx', See
# qemu-bridge-helper.c of qemu source code for details.
#
# The helper can be provided by package qemu-system-common on debian, or
# qemu-kvm-common on rhel
#
HELPER="${HELPER:-/usr/libexec/qemu-bridge-helper}"
### end of global settings
__errmsg() {
echo "$*" >&2
}
do_setup() {
# setup bridge for LAN network
sudo ip link add dev "$BR_LAN" type bridge
sudo ip link set dev "$BR_LAN" up
sudo ip addr add 192.168.1.3/24 dev "$BR_LAN"
# setup bridge for WAN network
#
# minimal dnsmasq config for configuring guest wan network with dhcp
#
# # sudo apt-get install dnsmasq
# # sudo vi /etc/dnsmasq.conf
# interface=br-wan
# dhcp-range=192.168.7.50,192.168.7.150,255.255.255.0,30m
#
sudo ip link add dev "$BR_WAN" type bridge
sudo ip link set dev "$BR_WAN" up
sudo ip addr add 192.168.7.1/24 dev "$BR_WAN"
# guest internet access
sudo sysctl -w "net.ipv4.ip_forward=1"
sudo sysctl -w "net.ipv4.conf.$BR_WAN.proxy_arp=1"
while sudo iptables -t nat -D POSTROUTING -o "$IF_INET" -j MASQUERADE 2>/dev/null; do true; done
sudo iptables -t nat -A POSTROUTING -o "$IF_INET" -j MASQUERADE
}
check_setup_() {
ip link show "$BR_LAN" >/dev/null || return 1
ip link show "$BR_WAN" >/dev/null || return 1
[ -x "$HELPER" ] || {
__errmsg "helper $HELPER is not an executable"
return 1
}
}
check_setup() {
[ -n "$o_network" ] || return 0
check_setup_ || {
__errmsg "please check the script content to see the environment requirement"
return 1
}
}
#do_setup; check_setup; exit $?
usage() {
cat >&2 <<EOF
Usage: $SELF [-h|--help]
$SELF <target>
[<subtarget> [<extra-qemu-options>]]
[--kernel <kernel>]
[--rootfs <rootfs>]
[--machine <machine>]
[-n|--network]
<subtarget> will default to "generic" and must be specified if
<extra-qemu-options> are present
e.g. <subtarget> for malta can be le, be, le64, be64, le-glibc, le64-glibc, etc
<kernel>, <rootfs> can be required or optional arguments to qemu depending on
the actual <target> in use. They will default to files under bin/targets/
Examples
$SELF x86 64
$SELF x86 64 --machine q35,accel=kvm -device virtio-balloon-pci
$SELF x86 64 -incoming tcp:0:4444
$SELF x86 64-glibc
$SELF malta be -m 64
$SELF malta le64
$SELF malta be-glibc
$SELF armvirt 32 \\
--machine virt,highmem=off \\
--kernel bin/targets/armvirt/32/openwrt-armvirt-32-zImage \\
--rootfs bin/targets/armvirt/32/openwrt-armvirt-32-root.ext4
EOF
}
rand_mac() {
hexdump -n 3 -e '"52:54:00" 3/1 ":%02x"' /dev/urandom
}
parse_args() {
o_network=
o_qemu_extra=()
while [ "$#" -gt 0 ]; do
# Cmdline options for the script itself SHOULD try to be
# prefixed with two dashes to distinguish them from those for
# qemu executables.
#
# Also note that qemu accepts both --opt and -opt
case "$1" in
--kernel) o_kernel="$2"; shift 2 ;;
--rootfs) o_rootfs="$2"; shift 2 ;;
--machine|-machine|-M) o_mach="$2"; shift 2 ;;
--network|-n) o_network=1; shift ;;
--help|-h)
usage
exit 0
;;
*)
if [ -z "$o_target" ]; then
o_target="$1"
elif [ -z "$o_subtarget" ]; then
o_subtarget="$1"
else
o_qemu_extra+=("$1")
fi
shift
;;
esac
done
MAC_LAN="$(rand_mac)"
MAC_WAN="$(rand_mac)"
[ -n "$o_target" ] || {
usage
return 1
}
[ -n "$o_subtarget" ] || o_subtarget="generic"
o_bindir="bin/targets/$o_target/$o_subtarget"
}
start_qemu_armvirt() {
local kernel="$o_kernel"
local rootfs="$o_rootfs"
local mach="${o_mach:-virt}"
local cpu
local qemu_exe
case "${o_subtarget%-*}" in
32)
qemu_exe="qemu-system-arm"
cpu="cortex-a15"
[ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-zImage-initramfs"
;;
64)
qemu_exe="qemu-system-aarch64"
cpu="cortex-a57"
[ -n "$kernel" ] || kernel="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-Image-initramfs"
;;
*)
__errmsg "target $o_target: unknown subtarget $o_subtarget"
return 1
;;
esac
[ -z "$rootfs" ] || {
if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
gunzip "$rootfs.gz"
fi
o_qemu_extra+=( \
"-drive" "file=$rootfs,format=raw,if=virtio" \
"-append" "root=/dev/vda rootwait" \
)
}
[ -z "$o_network" ] || {
o_qemu_extra+=( \
"-netdev" "bridge,id=lan,br=$BR_LAN,helper=$HELPER" \
"-device" "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN" \
"-netdev" "bridge,id=wan,br=$BR_WAN,helper=$HELPER" "-device" \
"virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN" \
)
}
"$qemu_exe" -machine "$mach" -cpu "$cpu" -nographic \
-kernel "$kernel" \
"${o_qemu_extra[@]}"
}
start_qemu_malta() {
local is64
local isel
local qemu_exe
local rootfs="$o_rootfs"
local kernel="$o_kernel"
local mach="${o_mach:-malta}"
# o_subtarget can be le, be, le64, be64, le-glibc, le64-glibc, etc..
is64="$(echo $o_subtarget | grep -o 64)"
[ "$(echo "$o_subtarget" | grep -o '^..')" = "le" ] && isel="el"
qemu_exe="qemu-system-mips$is64$isel"
[ -n "$kernel" ] || kernel="$o_bindir/openwrt-malta-${o_subtarget%-*}-vmlinux-initramfs.elf"
[ -z "$rootfs" ] || {
if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
gunzip "$rootfs.gz"
fi
o_qemu_extra+=( \
"-drive" "file=$rootfs,format=raw" \
"-append" "root=/dev/sda rootwait" \
)
}
# NOTE: order of wan, lan -device arguments matters as it will affect which
# one will be actually used as the wan, lan network interface inside the
# guest machine
[ -z "$o_network" ] || {
o_qemu_extra+=(
-netdev bridge,id=wan,br="$BR_WAN,helper=$HELPER" -device pcnet,netdev=wan,mac="$MAC_WAN"
-netdev bridge,id=lan,br="$BR_LAN,helper=$HELPER" -device pcnet,netdev=lan,mac="$MAC_LAN"
)
}
"$qemu_exe" -machine "$mach" -nographic \
-kernel "$kernel" \
"${o_qemu_extra[@]}"
}
start_qemu_x86() {
local qemu_exe
local kernel="$o_kernel"
local rootfs="$o_rootfs"
local mach="${o_mach:-pc}"
[ -n "$rootfs" ] || {
rootfs="$o_bindir/openwrt-$o_target-${o_subtarget%-*}-combined-ext4.img"
if [ ! -f "$rootfs" -a -s "$rootfs.gz" ]; then
gunzip "$rootfs.gz"
fi
}
#
# generic: 32-bit, pentium4 (CONFIG_MPENTIUM4), kvm guest, virtio
# legacy: 32-bit, i486 (CONFIG_M486)
# 64: 64-bit, kvm guest, virtio
#
case "${o_subtarget%-*}" in
legacy) qemu_exe="qemu-system-i386" ;;
generic|64) qemu_exe="qemu-system-x86_64" ;;
*)
__errmsg "target $o_target: unknown subtarget $o_subtarget"
return 1
;;
esac
[ -n "$kernel" ] && {
o_qemu_extra+=( \
"-kernel" "$kernel" \
"-append" "root=/dev/vda console=ttyS0 rootwait" \
)
}
[ -z "$o_network" ] || {
case "${o_subtarget%-*}" in
legacy)
o_qemu_extra+=(
-netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "e1000,id=devlan,netdev=lan,mac=$MAC_LAN"
-netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "e1000,id=devwan,netdev=wan,mac=$MAC_WAN"
)
;;
generic|64)
o_qemu_extra+=(
-netdev "bridge,id=lan,br=$BR_LAN,helper=$HELPER" -device "virtio-net-pci,id=devlan,netdev=lan,mac=$MAC_LAN"
-netdev "bridge,id=wan,br=$BR_WAN,helper=$HELPER" -device "virtio-net-pci,id=devwan,netdev=wan,mac=$MAC_WAN"
)
;;
esac
}
case "${o_subtarget%-*}" in
legacy)
# use IDE (PATA) disk instead of AHCI (SATA). Refer to link
# [1] for related discussions
#
# To use AHCI interface
#
# -device ich9-ahci,id=ahci \
# -device ide-drive,drive=drv0,bus=ahci.0 \
# -drive "file=$rootfs,format=raw,id=drv0,if=none" \
#
# [1] https://dev.openwrt.org/ticket/17947
"$qemu_exe" -machine "$mach" -nographic \
-device ide-drive,drive=drv0 \
-drive "file=$rootfs,format=raw,id=drv0,if=none" \
"${o_qemu_extra[@]}"
;;
generic|64)
"$qemu_exe" -machine "$mach" -nographic \
-drive "file=$rootfs,format=raw,if=virtio" \
"${o_qemu_extra[@]}"
;;
esac
}
start_qemu() {
case "$o_target" in
armvirt) start_qemu_armvirt ;;
malta) start_qemu_malta ;;
x86) start_qemu_x86 ;;
*)
__errmsg "target $o_target is not supported yet"
return 1
;;
esac
}
parse_args "$@" \
&& check_setup \
&& start_qemu

111
scripts/redboot-script.pl Executable file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/env perl
#
# Script for generating redboot configs, based on brcmImage.pl
#
# Copyright (C) 2015 Álvaro Fernández Rojas <noltari@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
use strict;
use Getopt::Std;
use File::stat;
my $version = "0.1";
my %arg = (
o => 'redboot.script',
s => 0x1000,
f => 0xbe430000,
a => 0x80010000,
l => 0x7c0000,
t => 20,
);
my $prog = $0;
$prog =~ s/^.*\///;
getopts("r:k:o:s:f:a:l:t:vh", \%arg);
die "usage: $prog ~opts~
-r <file> : input rootfs file
-k <file> : input kernel file
-o <file> : output image file, default $arg{o}
-s <size_kb> : redboot script size, default ".sprintf('%d', parse_num($arg{s}))."
-f <baseaddr> : flash base, default ".sprintf('0x%x', parse_num($arg{f}))."
-a <loadaddr> : Kernel load address, default ".sprintf('0x%x', parse_num($arg{a}))."
-l <linux_kb> : linux partition size, default ".sprintf('0x%x', parse_num($arg{l}))."
-t <timeout> : redboot script timeout, default ".sprintf('%d', parse_num($arg{t}))."
-v : be more verbose
-h : help, version $version
EXAMPLES:
$prog -k kern -r rootfs
" if $arg{h} || !$arg{k} || !$arg{r};
sub parse_num
{
my $num = @_[0];
if (index(lc($num), lc("0x")) == 0) {
return hex($num);
} else {
return $num + 0;
}
}
sub gen_script
{
my $kernel_off = parse_num($arg{s});
my $kernel_addr = parse_num($arg{f});
my $kernel_len = stat($arg{k})->size;
my $rootfs_off = $kernel_off + $kernel_len;
my $rootfs_addr = $kernel_addr + $kernel_len;
my $rootfs_len = parse_num($arg{l}) - $kernel_len;
my $rootfs_size = stat($arg{r})->size;
my $load_addr = parse_num($arg{a});
my $timeout = parse_num($arg{t});
if ($arg{v}) {
printf "kernel_off: 0x%x(%u)\n", $kernel_off, $kernel_off;
printf "kernel_addr: 0x%x(%u)\n", $kernel_addr, $kernel_addr;
printf "kernel_len: 0x%x(%u)\n", $kernel_len, $kernel_len;
printf "rootfs_off: 0x%x(%u)\n", $rootfs_off, $rootfs_off;
printf "rootfs_addr: 0x%x(%u)\n", $rootfs_addr, $rootfs_addr;
printf "rootfs_len: 0x%x(%u)\n", $rootfs_len, $rootfs_len;
printf "rootfs_size: 0x%x(%u)\n", $rootfs_size, $rootfs_size;
}
open(FO, ">$arg{o}");
printf FO "fis init -f\n";
printf FO "\n";
printf FO "fconfig boot_script true\n";
printf FO "fconfig boot_script_data\n";
printf FO "fis load -b 0x%x -d kernel\n", $load_addr;
printf FO "exec -c \"noinitrd\" 0x%x\n", $load_addr;
printf FO "\n";
printf FO "fconfig boot_script_timeout %d\n", $timeout;
printf FO "\n";
printf FO "fis create -o 0x%x -f 0x%x -l 0x%x kernel\n", $kernel_off, $kernel_addr, $kernel_len;
printf FO "\n";
printf FO "fis create -o 0x%x -s 0x%x -f 0x%x -l 0x%x rootfs\n", $rootfs_off, $rootfs_size, $rootfs_addr, $rootfs_len;
printf FO "\n";
printf FO "reset\n";
close FO;
}
# MAIN
gen_script();

14
scripts/relink-lib.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
[ $# -lt 4 -o -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ] && {
echo "Usage: $0 <cross> <reference> <pic .a> <destination>"
exit 1
}
cross="$1"; shift
ref="$1"; shift
pic="$1"; shift
dest="$1"; shift
SYMBOLS="$(${cross}nm "$ref" | grep -E '........ [TW] ' | awk '$3 {printf "-u%s ", $3}')"
set -x
${cross}gcc -nostdlib -nostartfiles -shared -Wl,--gc-sections -o "$dest" $SYMBOLS "$pic" "$@"

89
scripts/remote-gdb Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin '$Bin';
use File::Temp 'tempfile';
@ARGV == 2 || do {
die "Usage: $0 <corefile|host:port> <executable>\n";
exit 1;
};
if( opendir SD, "$Bin/../staging_dir" )
{
my ( $tid, $arch, $libc, @arches );
if( $ARGV[1] =~ m!\btarget-(.+?)_([^/_]+libc|musl)_?([^/]*).*\b!i )
{
print("Using target $1 ($2, $3)\n");
($arch, $libc) = ($1, $2);
}
else
{
# Find arches
print("Choose target:\n");
while( defined( my $e = readdir SD ) )
{
if( -d "$Bin/../staging_dir/$e" && $e =~ /^target-(.+?)_([^\/_]+libc|musl)_?([^\/]*).*/i )
{
push @arches, [ $1, $2 ];
printf(" %2d) %s (%s %s)\n", @arches + 0, $1, $2, $3);
}
}
if( @arches > 1 )
{
# Query arch
do {
print("Target? > ");
chomp($tid = <STDIN>);
} while( !defined($tid) || $tid !~ /^\d+$/ || $tid < 1 || $tid > @arches );
($arch, $libc) = @{$arches[$tid-1]};
}
else
{
($arch, $libc) = @{$arches[0]};
}
}
closedir SD;
# Find gdb
my ($gdb) = glob("$Bin/../staging_dir/toolchain-${arch}_*_${libc}*/bin/*-gdb");
if( defined($gdb) && -x $gdb )
{
my ( $fh, $fp ) = tempfile();
# Find sysroot
my ($sysroot) = glob("$Bin/../staging_dir/target-${arch}_${libc}*/root-*/");
print $fh "set sysroot $sysroot\n" if $sysroot;
my $cmd = "target extended-remote";
-f $ARGV[0] and $cmd = "core-file";
print $fh "$cmd $ARGV[0]\n";
# History settings
print $fh "set history filename $Bin/../tmp/.gdb_history\n";
print $fh "set history size 100000000\n";
print $fh "set history save on\n";
my $file = -f "$sysroot/$ARGV[1]" ? "$sysroot/$ARGV[1]" : $ARGV[1];
system($gdb, '-x', $fp, $file);
close($fh);
unlink($fp);
}
else
{
print("No gdb found! Make sure that CONFIG_GDB is set!\n");
exit(1);
}
}
else
{
print("No staging_dir found! You need to compile at least once!\n");
exit(1);
}

49
scripts/rstrip.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
SELF=${0##*/}
[ -z "$STRIP" ] && {
echo "$SELF: strip command not defined (STRIP variable not set)"
exit 1
}
TARGETS=$*
[ -z "$TARGETS" ] && {
echo "$SELF: no directories / files specified"
echo "usage: $SELF [PATH...]"
exit 1
}
find $TARGETS -type f -a -exec file {} \; | \
sed -n -e 's/^\(.*\):.*ELF.*\(executable\|relocatable\|shared object\).*,.*/\1:\2/p' | \
(
IFS=":"
while read F S; do
echo "$SELF: $F: $S"
[ "${S}" = "relocatable" ] && {
eval "$STRIP_KMOD $F"
} || {
b=$(stat -c '%a' $F)
[ -z "$PATCHELF" ] || [ -z "$TOPDIR" ] || {
old_rpath="$($PATCHELF --print-rpath $F)"; new_rpath=""
for path in $old_rpath; do
case "$path" in
/lib/[^/]*|/usr/lib/[^/]*|\$ORIGIN/*|\$ORIGIN) new_rpath="${new_rpath:+$new_rpath:}$path" ;;
*) echo "$SELF: $F: removing rpath $path" ;;
esac
done
[ "$new_rpath" = "$old_rpath" ] || $PATCHELF --set-rpath "$new_rpath" $F
}
eval "$STRIP $F"
a=$(stat -c '%a' $F)
[ "$a" = "$b" ] || chmod $b $F
}
done
true
)

1217
scripts/slugimage.pl Executable file

File diff suppressed because it is too large Load Diff

57
scripts/srecimage.pl Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env perl
#
# srecimage.pl - script to convert a binary image into srec
# Copyright (c) 2015 - Jo-Philipp Wich <jo@mein.io>
#
# This script is in the public domain.
use strict;
my ($input, $output, $offset) = @ARGV;
if (!defined($input) || !-f $input || !defined($output) ||
!defined($offset) || $offset !~ /^(0x)?[a-fA-F0-9]+$/) {
die "Usage: $0 <input file> <output file> <load address>\n";
}
sub srec
{
my ($type, $addr, $data, $len) = @_;
my @addrtypes = qw(%04X %04X %06X %08X %08X %04X %06X %08X %06X %04X);
my $addrstr = sprintf $addrtypes[$type], $addr;
$len = length($data) if ($len <= 0);
$len += 1 + (length($addrstr) / 2);
my $sum = $len;
foreach my $byte (unpack('C*', pack('H*', $addrstr)), unpack('C*', $data))
{
$sum += $byte;
}
return sprintf "S%d%02X%s%s%02X\r\n",
$type, $len, $addrstr, uc(unpack('H*', $data)), ~($sum & 0xFF) & 0xFF;
}
open(IN, '<:raw', $input) || die "Unable to open $input: $!\n";
open(OUT, '>:raw', $output) || die "Unable to open $output: $!\n";
my ($basename) = $output =~ m!([^/]+)$!;
print OUT srec(0, 0, $basename, 0);
my $off = hex($offset);
my $len;
while (defined($len = read(IN, my $buf, 16)) && $len > 0)
{
print OUT srec(3, $off, $buf, $len);
$off += $len;
}
print OUT srec(7, hex($offset), "", 0);
close OUT;
close IN;

55
scripts/strip-kmod.sh Executable file
View File

@@ -0,0 +1,55 @@
#!/usr/bin/env bash
[ -n "$CROSS" ] || {
echo "The variable CROSS must be set to point to the cross-compiler prefix"
exit 1
}
MODULE="$1"
[ "$#" -ne 1 ] && {
echo "Usage: $0 <module>"
exit 1
}
ARGS=
if [ -n "$KEEP_SYMBOLS" ]; then
ARGS="-X --strip-debug"
else
ARGS="-x -G __this_module --strip-unneeded"
fi
if [ -z "$KEEP_BUILD_ID" ]; then
ARGS="$ARGS -R .note.gnu.build-id"
fi
${CROSS}objcopy \
-R .comment \
-R .pdr \
-R .mdebug.abi32 \
-R .gnu.attributes \
-R .reginfo \
-R .MIPS.abiflags \
-R .note.GNU-stack \
$ARGS \
"$MODULE" "$MODULE.tmp"
[ -n "$NO_RENAME" ] && {
mv "${MODULE}.tmp" "$MODULE"
exit 0
}
${CROSS}nm "$MODULE.tmp" | awk '
BEGIN {
n = 0
}
$3 && $2 ~ /[brtd]/ && $3 !~ /\$LC/ && !def[$3] {
print "--redefine-sym "$3"=_"n;
n = n + 1
def[$3] = 1
}
' > "$MODULE.tmp1"
${CROSS}objcopy `cat ${MODULE}.tmp1` ${MODULE}.tmp ${MODULE}.out
mv "${MODULE}.out" "${MODULE}"
rm -f "${MODULE}".t*

51
scripts/symlink-tree.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Create a new openwrt tree with symlinks pointing at the current tree
# Usage: ./scripts/symlink-tree.sh <destination>
FILES="
BSDmakefile
config
Config.in
LICENSE
Makefile
README
dl
feeds.conf.default
include
package
rules.mk
scripts
target
toolchain
tools"
OPTIONAL_FILES="
.git"
if [ -f feeds.conf ] ; then
FILES="$FILES feeds.conf"
fi
if [ -z "$1" ]; then
echo "Syntax: $0 <destination>" >&2
exit 1
fi
if [ -e "$1" ]; then
echo "Error: $1 already exists" >&2
exit 1
fi
set -e # fail if any commands fails
mkdir -p dl "$1"
for file in $FILES; do
[ -e "$PWD/$file" ] || {
echo "ERROR: $file does not exist in the current tree" >&2
exit 1
}
ln -s "$PWD/$file" "$1/"
done
for file in $OPTIONAL_FILES; do
[ -e "$PWD/$file" ] && ln -s "$PWD/$file" "$1/"
done
exit 0

73
scripts/sysupgrade-tar.sh Executable file
View File

@@ -0,0 +1,73 @@
#!/bin/sh
board=""
kernel=""
rootfs=""
outfile=""
err=""
while [ "$1" ]; do
case "$1" in
"--board")
board="$2"
shift
shift
continue
;;
"--kernel")
kernel="$2"
shift
shift
continue
;;
"--rootfs")
rootfs="$2"
shift
shift
continue
;;
*)
if [ ! "$outfile" ]; then
outfile=$1
shift
continue
fi
;;
esac
done
if [ ! -n "$board" -o ! -r "$kernel" -a ! -r "$rootfs" -o ! "$outfile" ]; then
echo "syntax: $0 [--board boardname] [--kernel kernelimage] [--rootfs rootfs] out"
exit 1
fi
tmpdir="$( mktemp -d 2> /dev/null )"
if [ -z "$tmpdir" ]; then
# try OSX signature
tmpdir="$( mktemp -t 'ubitmp' -d )"
fi
if [ -z "$tmpdir" ]; then
exit 1
fi
mkdir -p "${tmpdir}/sysupgrade-${board}"
echo "BOARD=${board}" > "${tmpdir}/sysupgrade-${board}/CONTROL"
[ -z "${rootfs}" ] || cp "${rootfs}" "${tmpdir}/sysupgrade-${board}/root"
[ -z "${kernel}" ] || cp "${kernel}" "${tmpdir}/sysupgrade-${board}/kernel"
mtime=""
if [ -n "$SOURCE_DATE_EPOCH" ]; then
mtime="--mtime=@${SOURCE_DATE_EPOCH}"
fi
(cd "$tmpdir"; tar --sort=name --owner=0 --group=0 --numeric-owner -cvf sysupgrade.tar sysupgrade-${board} ${mtime})
err="$?"
if [ -e "$tmpdir/sysupgrade.tar" ]; then
cp "$tmpdir/sysupgrade.tar" "$outfile"
else
err=2
fi
rm -rf "$tmpdir"
exit $err

456
scripts/target-metadata.pl Executable file
View File

@@ -0,0 +1,456 @@
#!/usr/bin/env perl
use FindBin;
use lib "$FindBin::Bin";
use strict;
use metadata;
use Getopt::Long;
sub target_config_features(@) {
my $ret;
while ($_ = shift @_) {
/^arm_v(\w+)$/ and $ret .= "\tselect arm_v$1\n";
/^broken$/ and $ret .= "\tdepends on BROKEN\n";
/^audio$/ and $ret .= "\tselect AUDIO_SUPPORT\n";
/^display$/ and $ret .= "\tselect DISPLAY_SUPPORT\n";
/^dt$/ and $ret .= "\tselect USES_DEVICETREE\n";
/^gpio$/ and $ret .= "\tselect GPIO_SUPPORT\n";
/^pci$/ and $ret .= "\tselect PCI_SUPPORT\n";
/^pcie$/ and $ret .= "\tselect PCIE_SUPPORT\n";
/^usb$/ and $ret .= "\tselect USB_SUPPORT\n";
/^usbgadget$/ and $ret .= "\tselect USB_GADGET_SUPPORT\n";
/^pcmcia$/ and $ret .= "\tselect PCMCIA_SUPPORT\n";
/^rtc$/ and $ret .= "\tselect RTC_SUPPORT\n";
/^squashfs$/ and $ret .= "\tselect USES_SQUASHFS\n";
/^jffs2$/ and $ret .= "\tselect USES_JFFS2\n";
/^jffs2_nand$/ and $ret .= "\tselect USES_JFFS2_NAND\n";
/^ext4$/ and $ret .= "\tselect USES_EXT4\n";
/^targz$/ and $ret .= "\tselect USES_TARGZ\n";
/^cpiogz$/ and $ret .= "\tselect USES_CPIOGZ\n";
/^minor$/ and $ret .= "\tselect USES_MINOR\n";
/^ubifs$/ and $ret .= "\tselect USES_UBIFS\n";
/^fpu$/ and $ret .= "\tselect HAS_FPU\n";
/^spe_fpu$/ and $ret .= "\tselect HAS_SPE_FPU\n";
/^ramdisk$/ and $ret .= "\tselect USES_INITRAMFS\n";
/^powerpc64$/ and $ret .= "\tselect powerpc64\n";
/^nommu$/ and $ret .= "\tselect NOMMU\n";
/^mips16$/ and $ret .= "\tselect HAS_MIPS16\n";
/^rfkill$/ and $ret .= "\tselect RFKILL_SUPPORT\n";
/^low_mem$/ and $ret .= "\tselect LOW_MEMORY_FOOTPRINT\n";
/^small_flash$/ and $ret .= "\tselect SMALL_FLASH\n";
/^nand$/ and $ret .= "\tselect NAND_SUPPORT\n";
/^virtio$/ and $ret .= "\tselect VIRTIO_SUPPORT\n";
/^rootfs-part$/ and $ret .= "\tselect USES_ROOTFS_PART\n";
/^boot-part$/ and $ret .= "\tselect USES_BOOT_PART\n";
/^testing-kernel$/ and $ret .= "\tselect HAS_TESTING_KERNEL\n";
}
return $ret;
}
sub target_name($) {
my $target = shift;
my $parent = $target->{parent};
if ($parent) {
return $target->{parent}->{name}." - ".$target->{name};
} else {
return $target->{name};
}
}
sub kver($) {
my $v = shift;
$v =~ tr/\./_/;
if (substr($v,0,2) eq "2_") {
$v =~ /(\d+_\d+_\d+)(_\d+)?/ and $v = $1;
} else {
$v =~ /(\d+_\d+)(_\d+)?/ and $v = $1;
}
return $v;
}
sub print_target($) {
my $target = shift;
my $features = target_config_features(@{$target->{features}});
my $help = $target->{desc};
my $confstr;
chomp $features;
$features .= "\n";
if ($help =~ /\w+/) {
$help =~ s/^\s*/\t /mg;
$help = "\thelp\n$help";
} else {
undef $help;
}
my $v = kver($target->{version});
my $tv = kver($target->{testing_version});
$tv or $tv = $v;
if (@{$target->{subtargets}} == 0) {
$confstr = <<EOF;
config TARGET_$target->{conf}
bool "$target->{name}"
select LINUX_$v if !TESTING_KERNEL
select LINUX_$tv if TESTING_KERNEL
EOF
}
else {
$confstr = <<EOF;
config TARGET_$target->{conf}
bool "$target->{name}"
EOF
}
if ($target->{subtarget}) {
$confstr .= "\tdepends on TARGET_$target->{boardconf}\n";
}
if (@{$target->{subtargets}} > 0) {
$confstr .= "\tselect HAS_SUBTARGETS\n";
grep { /broken/ } @{$target->{features}} and $confstr .= "\tdepends on BROKEN\n";
} else {
$confstr .= $features;
if ($target->{arch} =~ /\w/) {
$confstr .= "\tselect $target->{arch}\n";
}
if ($target->{has_devices}) {
$confstr .= "\tselect HAS_DEVICES\n";
}
}
foreach my $dep (@{$target->{depends}}) {
my $mode = "depends on";
my $flags;
my $name;
$dep =~ /^([@\+\-]+)(.+)$/;
$flags = $1;
$name = $2;
next if $name =~ /:/;
$flags =~ /-/ and $mode = "deselect";
$flags =~ /\+/ and $mode = "select";
$flags =~ /@/ and $confstr .= "\t$mode $name\n";
}
$confstr .= "$help\n\n";
print $confstr;
}
sub merge_package_lists($$) {
my $list1 = shift;
my $list2 = shift;
my @l = ();
my %pkgs;
foreach my $pkg (@$list1, @$list2) {
$pkgs{$pkg} = 1;
}
foreach my $pkg (keys %pkgs) {
push @l, $pkg unless ($pkg =~ /^-/ or $pkgs{"-$pkg"});
}
return sort(@l);
}
sub gen_target_config() {
my $file = shift @ARGV;
my @target = parse_target_metadata($file);
my %defaults;
my @target_sort = sort {
target_name($a) cmp target_name($b);
} @target;
foreach my $target (@target_sort) {
next if @{$target->{subtargets}} > 0;
print <<EOF;
config DEFAULT_TARGET_$target->{conf}
bool
depends on TARGET_PER_DEVICE_ROOTFS
default y if TARGET_$target->{conf}
EOF
foreach my $pkg (@{$target->{packages}}) {
print "\tselect DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
}
}
print <<EOF;
choice
prompt "Target System"
default TARGET_ath79
reset if !DEVEL
EOF
foreach my $target (@target_sort) {
next if $target->{subtarget};
print_target($target);
}
print <<EOF;
endchoice
choice
prompt "Subtarget" if HAS_SUBTARGETS
EOF
foreach my $target (@target) {
next unless $target->{def_subtarget};
print <<EOF;
default TARGET_$target->{conf}_$target->{def_subtarget} if TARGET_$target->{conf}
EOF
}
print <<EOF;
EOF
foreach my $target (@target) {
next unless $target->{subtarget};
print_target($target);
}
print <<EOF;
endchoice
choice
prompt "Target Profile"
default TARGET_MULTI_PROFILE if BUILDBOT
EOF
foreach my $target (@target) {
my $profile = $target->{profiles}->[0];
$profile or next;
print <<EOF;
default TARGET_$target->{conf}_$profile->{id} if TARGET_$target->{conf} && !BUILDBOT
EOF
}
print <<EOF;
config TARGET_MULTI_PROFILE
bool "Multiple devices"
depends on HAS_DEVICES
help
Instead of only building a single image, or all images, this allows you
to select images to be built for multiple devices in one build.
EOF
foreach my $target (@target) {
my $profiles = $target->{profiles};
foreach my $profile (@{$target->{profiles}}) {
print <<EOF;
config TARGET_$target->{conf}_$profile->{id}
bool "$profile->{name}"
depends on TARGET_$target->{conf}
EOF
my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
foreach my $pkg (@pkglist) {
print "\tselect DEFAULT_$pkg\n";
$defaults{$pkg} = 1;
}
my $help = $profile->{desc};
if ($help =~ /\w+/) {
$help =~ s/^\s*/\t /mg;
$help = "\thelp\n$help";
} else {
undef $help;
}
print "$help\n";
}
}
print <<EOF;
endchoice
menu "Target Devices"
depends on TARGET_MULTI_PROFILE
config TARGET_ALL_PROFILES
bool "Enable all profiles by default"
default BUILDBOT
config TARGET_PER_DEVICE_ROOTFS
bool "Use a per-device root filesystem that adds profile packages"
default BUILDBOT
help
When disabled, all device packages from all selected devices
will be included in all images by default. (Marked as <*>) You will
still be able to manually deselect any/all packages.
When enabled, each device builds it's own image, including only the
profile packages for that device. (Marked as {M}) You will be able
to change a package to included in all images by marking as {*}, but
will not be able to disable a profile package completely.
To get the most use of this setting, you must set in a .config stub
before calling "make defconfig". Selecting TARGET_MULTI_PROFILE and
then manually selecting (via menuconfig for instance) this option
will have pre-defaulted all profile packages to included, making this
option appear to have had no effect.
EOF
foreach my $target (@target) {
my @profiles = sort {
my $x = $a->{name};
my $y = $b->{name};
"\L$x" cmp "\L$y";
} @{$target->{profiles}};
foreach my $profile (@profiles) {
next unless $profile->{id} =~ /^DEVICE_/;
print <<EOF;
menuconfig TARGET_DEVICE_$target->{conf}_$profile->{id}
bool "$profile->{name}"
depends on TARGET_$target->{conf}
default $profile->{default}
EOF
my @pkglist = merge_package_lists($target->{packages}, $profile->{packages});
foreach my $pkg (@pkglist) {
print "\tselect DEFAULT_$pkg if !TARGET_PER_DEVICE_ROOTFS\n";
print "\tselect MODULE_DEFAULT_$pkg if TARGET_PER_DEVICE_ROOTFS\n";
$defaults{$pkg} = 1;
}
print <<EOF;
config TARGET_DEVICE_PACKAGES_$target->{conf}_$profile->{id}
string "$profile->{name} additional packages"
default ""
depends on TARGET_PER_DEVICE_ROOTFS
depends on TARGET_DEVICE_$target->{conf}_$profile->{id}
EOF
}
}
print <<EOF;
endmenu
config HAS_SUBTARGETS
bool
config HAS_DEVICES
bool
config TARGET_BOARD
string
EOF
foreach my $target (@target) {
$target->{subtarget} or print "\t\tdefault \"".$target->{board}."\" if TARGET_".$target->{conf}."\n";
}
print <<EOF;
config TARGET_SUBTARGET
string
default "generic" if !HAS_SUBTARGETS
EOF
foreach my $target (@target) {
foreach my $subtarget (@{$target->{subtargets}}) {
print "\t\tdefault \"$subtarget\" if TARGET_".$target->{conf}."_$subtarget\n";
}
}
print <<EOF;
config TARGET_PROFILE
string
EOF
foreach my $target (@target) {
my $profiles = $target->{profiles};
foreach my $profile (@$profiles) {
print "\tdefault \"$profile->{id}\" if TARGET_$target->{conf}_$profile->{id}\n";
}
}
print <<EOF;
config TARGET_ARCH_PACKAGES
string
EOF
foreach my $target (@target) {
next if @{$target->{subtargets}} > 0;
print "\t\tdefault \"".($target->{arch_packages} || $target->{board})."\" if TARGET_".$target->{conf}."\n";
}
print <<EOF;
config DEFAULT_TARGET_OPTIMIZATION
string
EOF
foreach my $target (@target) {
next if @{$target->{subtargets}} > 0;
print "\tdefault \"".$target->{cflags}."\" if TARGET_".$target->{conf}."\n";
}
print "\tdefault \"-Os -pipe -funit-at-a-time\"\n";
print <<EOF;
config CPU_TYPE
string
EOF
foreach my $target (@target) {
next if @{$target->{subtargets}} > 0;
print "\tdefault \"".$target->{cputype}."\" if TARGET_".$target->{conf}."\n";
}
print "\tdefault \"\"\n";
my %kver;
foreach my $target (@target) {
foreach my $tv ($target->{version}, $target->{testing_version}) {
next unless $tv;
my $v = kver($tv);
next if $kver{$v};
$kver{$v} = 1;
print <<EOF;
config LINUX_$v
bool
EOF
}
}
foreach my $def (sort keys %defaults) {
print <<EOF;
config DEFAULT_$def
bool
config MODULE_DEFAULT_$def
tristate
depends on TARGET_PER_DEVICE_ROOTFS
depends on m
default m if DEFAULT_$def
select PACKAGE_$def
EOF
}
}
sub gen_profile_mk() {
my $file = shift @ARGV;
my $target = shift @ARGV;
my @targets = parse_target_metadata($file);
foreach my $cur (@targets) {
next unless $cur->{id} eq $target;
print "PROFILE_NAMES = ".join(" ", map { $_->{id} } @{$cur->{profiles}})."\n";
foreach my $profile (@{$cur->{profiles}}) {
print $profile->{id}.'_NAME:='.$profile->{name}."\n";
print $profile->{id}.'_HAS_IMAGE_METADATA:='.$profile->{has_image_metadata}."\n";
if (defined($profile->{supported_devices}) and @{$profile->{supported_devices}} > 0) {
print $profile->{id}.'_SUPPORTED_DEVICES:='.join(' ', @{$profile->{supported_devices}})."\n";
}
print $profile->{id}.'_PACKAGES:='.join(' ', @{$profile->{packages}})."\n";
}
}
}
sub parse_command() {
GetOptions("ignore=s", \@ignore);
my $cmd = shift @ARGV;
for ($cmd) {
/^config$/ and return gen_target_config();
/^profile_mk$/ and return gen_profile_mk();
}
die <<EOF
Available Commands:
$0 config [file] Target metadata in Kconfig format
$0 profile_mk [file] [target] Profile metadata in makefile format
EOF
}
parse_command();

65
scripts/time.pl Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Config;
if (@ARGV < 2) {
die "Usage: $0 <prefix> <command...>\n";
}
sub gettime {
my ($sec, $usec);
eval {
require Time::HiRes;
($sec, $usec) = Time::HiRes::gettimeofday();
};
unless (defined($sec) && defined($usec)) {
my $tv_t = ($Config{'longsize'} == 8) ? 'qq' : 'll';
my $tv = pack $tv_t, 0, 0;
eval {
require 'syscall.ph';
syscall(SYS_gettimeofday(), $tv, 0);
};
($sec, $usec) = unpack $tv_t, $tv;
}
return ($sec, $usec);
}
my ($prefix, @cmd) = @ARGV;
my ($sec, $usec) = gettime();
my $pid = fork();
if (!defined($pid)) {
die "$0: Failure to fork(): $!\n";
}
elsif ($pid == 0) {
exec(@cmd);
die "$0: Failure to exec(): $!\n";
}
else {
$SIG{'INT'} = 'IGNORE';
$SIG{'QUIT'} = 'IGNORE';
if (waitpid($pid, 0) == -1) {
die "$0: Failure to waitpid(): $!\n";
}
my $exitcode = $? >> 8;
my ($sec2, $usec2) = gettime();
my (undef, undef, $cuser, $csystem) = times();
printf STDOUT "%s#%.2f#%.2f#%.2f\n",
$prefix, $cuser, $csystem,
($sec2 - $sec) + ($usec2 - $usec) / 1000000;
$SIG{'INT'} = 'DEFAULT';
$SIG{'QUIT'} = 'DEFAULT';
exit $exitcode;
}

69
scripts/timestamp.pl Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env perl
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
use strict;
sub get_ts($$) {
my $path = shift;
my $options = shift;
my $ts = 0;
my $fn = "";
$path .= "/" if( -d $path);
open FIND, "find $path -type f -and -not -path \\*/.svn\\* -and -not -path \\*CVS\\* $options 2>/dev/null |";
while (<FIND>) {
chomp;
my $file = $_;
next if -l $file;
my $mt = (stat $file)[9];
if ($mt > $ts) {
$ts = $mt;
$fn = $file;
}
}
close FIND;
return ($ts, $fn);
}
(@ARGV > 0) or push @ARGV, ".";
my $ts = 0;
my $n = ".";
my %options;
while (@ARGV > 0) {
my $path = shift @ARGV;
if ($path =~ /^-x/) {
my $str = shift @ARGV;
$options{"findopts"} .= " -and -not -path '".$str."'"
} elsif ($path =~ /^-f/) {
$options{"findopts"} .= " -follow";
} elsif ($path =~ /^-n/) {
my $arg = $ARGV[0];
$options{$path} = $arg;
} elsif ($path =~ /^-/) {
$options{$path} = 1;
} else {
my ($tmp, $fname) = get_ts($path, $options{"findopts"});
if ($tmp > $ts) {
if ($options{'-F'}) {
$n = $fname;
} else {
$n = $path;
}
$ts = $tmp;
}
}
}
if ($options{"-n"}) {
exit ($n eq $options{"-n"} ? 0 : 1);
} elsif ($options{"-p"}) {
print "$n\n";
} elsif ($options{"-t"}) {
print "$ts\n";
} else {
print "$n\t$ts\n";
}

139
scripts/ubinize-image.sh Executable file
View File

@@ -0,0 +1,139 @@
#!/bin/sh
part=""
ubootenv=""
ubinize_param=""
kernel=""
rootfs=""
outfile=""
err=""
get_magic_word() {
dd if=$1 bs=2 count=1 2>/dev/null | od -A n -N 2 -t x1 | tr -d ' '
}
is_ubifs() {
if [ "$( get_magic_word $1 )" = "3118" ]; then
echo "1"
fi
}
ubivol() {
volid=$1
name=$2
image=$3
autoresize=$4
size="$5"
echo "[$name]"
echo "mode=ubi"
echo "vol_id=$volid"
echo "vol_type=dynamic"
echo "vol_name=$name"
if [ "$image" ]; then
echo "image=$image"
[ -n "$size" ] && echo "vol_size=${size}MiB"
else
echo "vol_size=1MiB"
fi
if [ "$autoresize" ]; then
echo "vol_flags=autoresize"
fi
}
ubilayout() {
local vol_id=0
local root_is_ubifs="$( is_ubifs "$2" )"
if [ "$1" = "ubootenv" ]; then
ubivol $vol_id ubootenv
vol_id=$(( $vol_id + 1 ))
ubivol $vol_id ubootenv2
vol_id=$(( $vol_id + 1 ))
fi
for part in $parts; do
name="${part%%=*}"
prev="$part"
part="${part#*=}"
[ "$prev" = "$part" ] && part=
image="${part%%=*}"
prev="$part"
part="${part#*=}"
[ "$prev" = "$part" ] && part=
size="$part"
ubivol $vol_id "$name" "$image" "" "$size"
vol_id=$(( $vol_id + 1 ))
done
if [ "$3" ]; then
ubivol $vol_id kernel "$3"
vol_id=$(( $vol_id + 1 ))
fi
ubivol $vol_id rootfs "$2" $root_is_ubifs
vol_id=$(( $vol_id + 1 ))
[ "$root_is_ubifs" ] || ubivol $vol_id rootfs_data "" 1
}
while [ "$1" ]; do
case "$1" in
"--uboot-env")
ubootenv="ubootenv"
shift
continue
;;
"--kernel")
kernel="$2"
shift
shift
continue
;;
"--part")
parts="$parts $2"
shift
shift
continue
;;
"-"*)
ubinize_param="$@"
break
;;
*)
if [ ! "$rootfs" ]; then
rootfs=$1
shift
continue
fi
if [ ! "$outfile" ]; then
outfile=$1
shift
continue
fi
;;
esac
done
if [ ! -r "$rootfs" -o ! -r "$kernel" -a ! "$outfile" ]; then
echo "syntax: $0 [--uboot-env] [--part <name>=<file>] [--kernel kernelimage] rootfs out [ubinize opts]"
exit 1
fi
ubinize="$( which ubinize )"
if [ ! -x "$ubinize" ]; then
echo "ubinize tool not found or not usable"
exit 1
fi
ubinizecfg="$( mktemp 2> /dev/null )"
if [ -z "$ubinizecfg" ]; then
# try OSX signature
ubinizecfg="$( mktemp -t 'ubitmp' )"
fi
ubilayout "$ubootenv" "$rootfs" "$kernel" > "$ubinizecfg"
cat "$ubinizecfg"
ubinize -o "$outfile" $ubinize_param "$ubinizecfg"
err="$?"
[ ! -e "$outfile" ] && err=2
rm "$ubinizecfg"
exit $err