mirror of
https://github.com/openharmony/third_party_toybox.git
synced 2026-06-30 21:37:54 -04:00
update openharmony 1.0.1
This commit is contained in:
+17
@@ -0,0 +1,17 @@
|
||||
syntax: glob
|
||||
/.config.old
|
||||
.single*
|
||||
change/
|
||||
/generated/build.sh
|
||||
/generated/cflags
|
||||
/generated/config2help
|
||||
/generated/Config.in
|
||||
/generated/Config.probed
|
||||
/generated/flags.raw
|
||||
/generated/mkflags
|
||||
/generated/mktags
|
||||
/generated/obj
|
||||
/generated/optlibs.dat
|
||||
/kconfig
|
||||
toybox
|
||||
toybox_unstripped
|
||||
@@ -0,0 +1,250 @@
|
||||
# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
|
||||
# Must do steps below manually after getting the sources code
|
||||
# from official website:
|
||||
# 1. make defconfig or make menuconfig
|
||||
# ==> To generate .config file.
|
||||
# 2. NOBUILD=1 scripts/make.sh
|
||||
# ==> To generate neccesary files like heades in generated
|
||||
# direcotory.
|
||||
|
||||
# To add a toy:
|
||||
# 1. Edit .config to enable the toy you want to add.
|
||||
# 2. Edit toybox'sources below if neccesary.
|
||||
# e. Add th toy to the symlinks.
|
||||
|
||||
import("//build/lite/config/component/lite_component.gni")
|
||||
|
||||
lite_component("toybox") {
|
||||
features = [ ":toybox-0.8.2" ]
|
||||
}
|
||||
|
||||
executable("toybox-0.8.2") {
|
||||
output_name = "toybox"
|
||||
|
||||
# from middleware file build.sh
|
||||
sources = [
|
||||
"lib/args.c",
|
||||
"lib/commas.c",
|
||||
"lib/deflate.c",
|
||||
"lib/dirtree.c",
|
||||
"lib/env.c",
|
||||
"lib/help.c",
|
||||
"lib/lib.c",
|
||||
"lib/linestack.c",
|
||||
"lib/llist.c",
|
||||
"lib/net.c",
|
||||
"lib/password.c",
|
||||
"lib/portability.c",
|
||||
"lib/tty.c",
|
||||
"lib/xwrap.c",
|
||||
"main.c",
|
||||
"toys/lsb/dmesg.c",
|
||||
"toys/lsb/gzip.c",
|
||||
"toys/lsb/hostname.c",
|
||||
"toys/lsb/killall.c",
|
||||
"toys/lsb/md5sum.c",
|
||||
"toys/lsb/mknod.c",
|
||||
"toys/lsb/mktemp.c",
|
||||
"toys/lsb/mount.c",
|
||||
"toys/lsb/passwd.c",
|
||||
"toys/lsb/pidof.c",
|
||||
"toys/lsb/seq.c",
|
||||
"toys/lsb/su.c",
|
||||
"toys/lsb/sync.c",
|
||||
"toys/lsb/umount.c",
|
||||
"toys/net/ftpget.c",
|
||||
"toys/net/ifconfig.c",
|
||||
"toys/net/microcom.c",
|
||||
"toys/net/netcat.c",
|
||||
"toys/net/netstat.c",
|
||||
"toys/net/ping.c",
|
||||
"toys/net/rfkill.c",
|
||||
"toys/net/sntp.c",
|
||||
"toys/net/tunctl.c",
|
||||
"toys/other/acpi.c",
|
||||
"toys/other/ascii.c",
|
||||
"toys/other/base64.c",
|
||||
"toys/other/blkid.c",
|
||||
"toys/other/blockdev.c",
|
||||
"toys/other/bzcat.c",
|
||||
"toys/other/chroot.c",
|
||||
"toys/other/chrt.c",
|
||||
"toys/other/chvt.c",
|
||||
"toys/other/clear.c",
|
||||
"toys/other/count.c",
|
||||
"toys/other/devmem.c",
|
||||
"toys/other/dos2unix.c",
|
||||
"toys/other/eject.c",
|
||||
"toys/other/factor.c",
|
||||
"toys/other/fallocate.c",
|
||||
"toys/other/flock.c",
|
||||
"toys/other/fmt.c",
|
||||
"toys/other/free.c",
|
||||
"toys/other/freeramdisk.c",
|
||||
"toys/other/fsfreeze.c",
|
||||
"toys/other/fsync.c",
|
||||
"toys/other/help.c",
|
||||
"toys/other/hexedit.c",
|
||||
"toys/other/hwclock.c",
|
||||
"toys/other/i2ctools.c",
|
||||
"toys/other/inotifyd.c",
|
||||
"toys/other/insmod.c",
|
||||
"toys/other/ionice.c",
|
||||
"toys/other/login.c",
|
||||
"toys/other/losetup.c",
|
||||
"toys/other/lsattr.c",
|
||||
"toys/other/lsmod.c",
|
||||
"toys/other/lspci.c",
|
||||
"toys/other/lsusb.c",
|
||||
"toys/other/makedevs.c",
|
||||
"toys/other/mcookie.c",
|
||||
"toys/other/mix.c",
|
||||
"toys/other/mkpasswd.c",
|
||||
"toys/other/mkswap.c",
|
||||
"toys/other/modinfo.c",
|
||||
"toys/other/mountpoint.c",
|
||||
"toys/other/nbd_client.c",
|
||||
"toys/other/nsenter.c",
|
||||
"toys/other/oneit.c",
|
||||
"toys/other/partprobe.c",
|
||||
"toys/other/pivot_root.c",
|
||||
"toys/other/pmap.c",
|
||||
"toys/other/printenv.c",
|
||||
"toys/other/pwdx.c",
|
||||
"toys/other/readahead.c",
|
||||
"toys/other/readlink.c",
|
||||
"toys/other/realpath.c",
|
||||
"toys/other/reboot.c",
|
||||
"toys/other/reset.c",
|
||||
"toys/other/rev.c",
|
||||
"toys/other/rmmod.c",
|
||||
"toys/other/setfattr.c",
|
||||
"toys/other/setsid.c",
|
||||
"toys/other/shred.c",
|
||||
"toys/other/stat.c",
|
||||
"toys/other/swapoff.c",
|
||||
"toys/other/swapon.c",
|
||||
"toys/other/switch_root.c",
|
||||
"toys/other/sysctl.c",
|
||||
"toys/other/tac.c",
|
||||
"toys/other/taskset.c",
|
||||
"toys/other/timeout.c",
|
||||
"toys/other/truncate.c",
|
||||
"toys/other/uptime.c",
|
||||
"toys/other/usleep.c",
|
||||
"toys/other/uuidgen.c",
|
||||
"toys/other/vconfig.c",
|
||||
"toys/other/vmstat.c",
|
||||
"toys/other/w.c",
|
||||
"toys/other/watch.c",
|
||||
"toys/other/which.c",
|
||||
"toys/other/xxd.c",
|
||||
"toys/other/yes.c",
|
||||
"toys/pending/bootchartd.c",
|
||||
"toys/pending/diff.c",
|
||||
"toys/pending/getty.c",
|
||||
"toys/pending/more.c",
|
||||
"toys/posix/basename.c",
|
||||
"toys/posix/cal.c",
|
||||
"toys/posix/cat.c",
|
||||
"toys/posix/chgrp.c",
|
||||
"toys/posix/chmod.c",
|
||||
"toys/posix/cksum.c",
|
||||
"toys/posix/cmp.c",
|
||||
"toys/posix/comm.c",
|
||||
"toys/posix/cp.c",
|
||||
"toys/posix/cpio.c",
|
||||
"toys/posix/cut.c",
|
||||
"toys/posix/date.c",
|
||||
"toys/posix/df.c",
|
||||
"toys/posix/dirname.c",
|
||||
"toys/posix/du.c",
|
||||
"toys/posix/echo.c",
|
||||
"toys/posix/env.c",
|
||||
"toys/posix/expand.c",
|
||||
"toys/posix/false.c",
|
||||
"toys/posix/file.c",
|
||||
"toys/posix/find.c",
|
||||
"toys/posix/getconf.c",
|
||||
"toys/posix/grep.c",
|
||||
"toys/posix/head.c",
|
||||
"toys/posix/iconv.c",
|
||||
"toys/posix/id.c",
|
||||
"toys/posix/kill.c",
|
||||
"toys/posix/link.c",
|
||||
"toys/posix/ln.c",
|
||||
"toys/posix/logger.c",
|
||||
"toys/posix/ls.c",
|
||||
"toys/posix/mkdir.c",
|
||||
"toys/posix/mkfifo.c",
|
||||
"toys/posix/nice.c",
|
||||
"toys/posix/nl.c",
|
||||
"toys/posix/nohup.c",
|
||||
"toys/posix/od.c",
|
||||
"toys/posix/paste.c",
|
||||
"toys/posix/patch.c",
|
||||
"toys/posix/printf.c",
|
||||
"toys/posix/ps.c",
|
||||
"toys/posix/pwd.c",
|
||||
"toys/posix/renice.c",
|
||||
"toys/posix/rm.c",
|
||||
"toys/posix/rmdir.c",
|
||||
"toys/posix/sed.c",
|
||||
"toys/posix/sleep.c",
|
||||
"toys/posix/sort.c",
|
||||
"toys/posix/split.c",
|
||||
"toys/posix/strings.c",
|
||||
"toys/posix/tail.c",
|
||||
"toys/posix/tar.c",
|
||||
"toys/posix/tee.c",
|
||||
"toys/posix/test.c",
|
||||
"toys/posix/time.c",
|
||||
"toys/posix/touch.c",
|
||||
"toys/posix/true.c",
|
||||
"toys/posix/tty.c",
|
||||
"toys/posix/ulimit.c",
|
||||
"toys/posix/uname.c",
|
||||
"toys/posix/uniq.c",
|
||||
"toys/posix/unlink.c",
|
||||
"toys/posix/uudecode.c",
|
||||
"toys/posix/uuencode.c",
|
||||
"toys/posix/wc.c",
|
||||
"toys/posix/who.c",
|
||||
"toys/posix/xargs.c",
|
||||
]
|
||||
|
||||
include_dirs = [ "./" ]
|
||||
|
||||
defines = [ "_DEFAULT_SOURCE" ]
|
||||
|
||||
configs -= [ "//build/lite/config:language_c" ]
|
||||
cflags_c = [
|
||||
"-std=gnu11",
|
||||
"-Wall",
|
||||
"-Wundef",
|
||||
"-Wno-char-subscripts",
|
||||
"-Wno-implicit-function-declaration",
|
||||
"-Wno-unused-variable",
|
||||
"-Wno-unused-value",
|
||||
"-Wno-incompatible-pointer-types",
|
||||
"-Wno-int-conversion",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-format",
|
||||
"-Wno-unused-result",
|
||||
"-Os",
|
||||
"-ffunction-sections",
|
||||
"-fdata-sections",
|
||||
"-fno-asynchronous-unwind-tables",
|
||||
"-fPIE",
|
||||
"-funsigned-char",
|
||||
]
|
||||
|
||||
ldflags = [
|
||||
"-pie",
|
||||
"-Wl,-z,relro",
|
||||
"-Wl,-z,now",
|
||||
"-Wl,-z,noexecstack",
|
||||
"-lm",
|
||||
"-lcrypt",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
mainmenu "Toybox Configuration"
|
||||
|
||||
|
||||
source generated/Config.probed
|
||||
source generated/Config.in
|
||||
|
||||
comment ""
|
||||
|
||||
menu "Toybox global settings"
|
||||
|
||||
# This entry controls the multiplexer, disabled for single command builds
|
||||
config TOYBOX
|
||||
bool
|
||||
default y
|
||||
help
|
||||
usage: toybox [--long | --help | --version | [command] [arguments...]]
|
||||
|
||||
With no arguments, shows available commands. First argument is
|
||||
name of a command to run, followed by any arguments to that command.
|
||||
|
||||
--long Show path to each command
|
||||
|
||||
To install command symlinks with paths, try:
|
||||
for i in $(/bin/toybox --long); do ln -s /bin/toybox $i; done
|
||||
or all in one directory:
|
||||
for i in $(./toybox); do ln -s toybox $i; done; PATH=$PWD:$PATH
|
||||
|
||||
Most toybox commands also understand the following arguments:
|
||||
|
||||
--help Show command help (only)
|
||||
--version Show toybox version (only)
|
||||
|
||||
The filename "-" means stdin/stdout, and "--" stops argument parsing.
|
||||
|
||||
Numerical arguments accept a single letter suffix for
|
||||
kilo, mega, giga, tera, peta, and exabytes, plus an additional
|
||||
"d" to indicate decimal 1000's instead of 1024.
|
||||
|
||||
Durations can be decimal fractions and accept minute ("m"), hour ("h"),
|
||||
or day ("d") suffixes (so 0.1m = 6s).
|
||||
|
||||
config TOYBOX_SUID
|
||||
bool "SUID support"
|
||||
default y
|
||||
help
|
||||
Support for the Set User ID bit, to install toybox suid root and drop
|
||||
permissions for commands which do not require root access. To use
|
||||
this change ownership of the file to the root user and set the suid
|
||||
bit in the file permissions:
|
||||
|
||||
chown root:root toybox; chmod +s toybox
|
||||
|
||||
choice
|
||||
prompt "Security Blanket"
|
||||
default TOYBOX_LSM_NONE
|
||||
help
|
||||
Select a Linux Security Module to complicate your system
|
||||
until you can't find holes in it.
|
||||
|
||||
config TOYBOX_LSM_NONE
|
||||
bool "None"
|
||||
help
|
||||
Don't try to achieve "watertight" by plugging the holes in a
|
||||
collander, instead use conventional unix security (and possibly
|
||||
Linux Containers) for a simple straightforward system.
|
||||
|
||||
config TOYBOX_SELINUX
|
||||
bool "SELinux support"
|
||||
help
|
||||
Include SELinux options in commands such as ls, and add
|
||||
SELinux-specific commands such as chcon to the Android menu.
|
||||
|
||||
config TOYBOX_SMACK
|
||||
bool "SMACK support"
|
||||
help
|
||||
Include SMACK options in commands like ls for systems like Tizen.
|
||||
|
||||
endchoice
|
||||
|
||||
config TOYBOX_LIBCRYPTO
|
||||
bool "Use libcrypto (OpenSSL/BoringSSL)"
|
||||
default n
|
||||
help
|
||||
Use faster hash functions out of external -lcrypto library.
|
||||
|
||||
config TOYBOX_LIBZ
|
||||
bool "Use libz (zlib)"
|
||||
default n
|
||||
help
|
||||
Use libz for gz support.
|
||||
|
||||
config TOYBOX_FLOAT
|
||||
bool "Floating point support"
|
||||
default y
|
||||
help
|
||||
Include floating point support infrastructure and commands that
|
||||
require it.
|
||||
|
||||
config TOYBOX_HELP
|
||||
bool "Help messages"
|
||||
default y
|
||||
help
|
||||
Include help text for each command.
|
||||
|
||||
config TOYBOX_HELP_DASHDASH
|
||||
bool "--help and --version"
|
||||
default y
|
||||
depends on TOYBOX_HELP
|
||||
help
|
||||
Support --help argument in all commands, even ones with a NULL
|
||||
optstring. (Use TOYFLAG_NOHELP to disable.) Produces the same output
|
||||
as "help command". --version shows toybox version.
|
||||
|
||||
config TOYBOX_I18N
|
||||
bool "Internationalization support"
|
||||
default y
|
||||
help
|
||||
Support for UTF-8 character sets, and some locale support.
|
||||
|
||||
config TOYBOX_FREE
|
||||
bool "Free memory unnecessarily"
|
||||
default n
|
||||
help
|
||||
When a program exits, the operating system will clean up after it
|
||||
(free memory, close files, etc). To save size, toybox usually relies
|
||||
on this behavior. If you're running toybox under a debugger or
|
||||
without a real OS (ala newlib+libgloss), enable this to make toybox
|
||||
clean up after itself.
|
||||
|
||||
config TOYBOX_NORECURSE
|
||||
bool "Disable recursive execution"
|
||||
default n
|
||||
help
|
||||
When one toybox command calls another, usually it just calls the new
|
||||
command's main() function rather than searching the $PATH and calling
|
||||
exec on another file (which is much slower).
|
||||
|
||||
This disables that optimization, so toybox will run external commands
|
||||
even when it has a built-in version of that command. This requires
|
||||
toybox symlinks to be installed in the $PATH, or re-invoking the
|
||||
"toybox" multiplexer command by name.
|
||||
|
||||
config TOYBOX_DEBUG
|
||||
bool "Debugging tests"
|
||||
default n
|
||||
help
|
||||
Enable extra checks for debugging purposes. All of them catch
|
||||
things that can only go wrong at development time, not runtime.
|
||||
|
||||
config TOYBOX_PEDANTIC_ARGS
|
||||
bool "Pedantic argument checking"
|
||||
default n
|
||||
help
|
||||
Check arguments for commands that have no arguments.
|
||||
|
||||
config TOYBOX_UID_SYS
|
||||
int "First system UID"
|
||||
default 100
|
||||
help
|
||||
When commands like useradd/groupadd allocate system IDs, start here.
|
||||
|
||||
config TOYBOX_UID_USR
|
||||
int "First user UID"
|
||||
default 500
|
||||
help
|
||||
When commands like useradd/groupadd allocate user IDs, start here.
|
||||
|
||||
config TOYBOX_MUSL_NOMMU_IS_BROKEN
|
||||
bool "Workaround for musl-libc breakage on nommu systems."
|
||||
default n
|
||||
help
|
||||
When using musl-libc on a nommu system, you'll need to say "y" here.
|
||||
|
||||
Although uclibc lets you detect support for things like fork() and
|
||||
daemon() at compile time, musl intentionally includes broken versions
|
||||
that always return -ENOSYS on nommu systems, and goes out of its way
|
||||
to prevent any cross-compile compatible compile-time probes for a
|
||||
nommu system. (It doesn't even #define __MUSL__ in features.h.)
|
||||
|
||||
Musl does this despite the fact that a nommu system can't even run
|
||||
standard ELF binaries, and requires specially packaged executables.
|
||||
So our only choice is to manually provide a musl nommu bug workaround
|
||||
you can manually select to enable (larger, slower) nommu support with
|
||||
musl.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,12 @@
|
||||
Copyright (C) 2006, 2019 by Rob Landley <rob@landley.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Makefile for toybox.
|
||||
# Copyright 2006 Rob Landley <rob@landley.net>
|
||||
|
||||
# If people set these on the make command line, use 'em
|
||||
# Note that CC defaults to "cc" so the one in configure doesn't get
|
||||
# used when scripts/make.sh and care called through "make".
|
||||
|
||||
HOSTCC?=cc
|
||||
|
||||
export CROSS_COMPILE CFLAGS OPTIMIZE LDOPTIMIZE CC HOSTCC V STRIP
|
||||
|
||||
all: toybox
|
||||
|
||||
KCONFIG_CONFIG ?= .config
|
||||
|
||||
toybox_stuff: $(KCONFIG_CONFIG) *.[ch] lib/*.[ch] toys/*/*.c scripts/*.sh
|
||||
|
||||
toybox generated/unstripped/toybox: toybox_stuff
|
||||
scripts/make.sh
|
||||
|
||||
.PHONY: clean distclean baseline bloatcheck install install_flat \
|
||||
uinstall uninstall_flat tests help toybox_stuff change \
|
||||
list list_working list_pending root run_root
|
||||
|
||||
include kconfig/Makefile
|
||||
-include .singlemake
|
||||
|
||||
$(KCONFIG_CONFIG): $(KCONFIG_TOP)
|
||||
@if [ -e "$(KCONFIG_CONFIG)" ]; then make silentoldconfig; \
|
||||
else echo "Not configured (run 'make defconfig' or 'make menuconfig')";\
|
||||
exit 1; fi
|
||||
|
||||
$(KCONFIG_TOP): generated/Config.in generated/Config.probed
|
||||
generated/Config.probed: generated/Config.in
|
||||
generated/Config.in: toys/*/*.c scripts/genconfig.sh
|
||||
scripts/genconfig.sh
|
||||
|
||||
# Development targets
|
||||
baseline: generated/unstripped/toybox
|
||||
@cp generated/unstripped/toybox generated/unstripped/toybox_old
|
||||
|
||||
bloatcheck: generated/unstripped/toybox_old generated/unstripped/toybox
|
||||
@scripts/bloatcheck generated/unstripped/toybox_old generated/unstripped/toybox
|
||||
|
||||
install_flat:
|
||||
scripts/install.sh --symlink --force
|
||||
|
||||
install_airlock:
|
||||
scripts/install.sh --symlink --force --airlock
|
||||
|
||||
install:
|
||||
scripts/install.sh --long --symlink --force
|
||||
|
||||
uninstall_flat:
|
||||
scripts/install.sh --uninstall
|
||||
|
||||
uninstall:
|
||||
scripts/install.sh --long --uninstall
|
||||
|
||||
change:
|
||||
scripts/change.sh
|
||||
|
||||
root_clean:
|
||||
@rm -rf root
|
||||
@echo root cleaned
|
||||
|
||||
clean::
|
||||
@rm -rf toybox generated change .singleconfig* cross-log-*.*
|
||||
@echo cleaned
|
||||
|
||||
# If singlemake was in generated/ "make clean; make test_ls" wouldn't work.
|
||||
distclean: clean root_clean
|
||||
@rm -f toybox* .config* .singlemake
|
||||
@echo removed .config
|
||||
|
||||
tests:
|
||||
scripts/test.sh
|
||||
|
||||
root:
|
||||
scripts/mkroot.sh $(MAKEFLAGS)
|
||||
|
||||
run_root:
|
||||
C=$$(basename "$$CROSS_COMPILE" | sed 's/-.*//'); \
|
||||
cd root/"$${C:-host}" && ./qemu-*.sh $(MAKEFLAGS) || exit 1
|
||||
|
||||
help::
|
||||
@cat scripts/help.txt
|
||||
@@ -0,0 +1,169 @@
|
||||
Toybox: all-in-one Linux command line.
|
||||
|
||||
--- Getting started
|
||||
|
||||
You can download static binaries for various targets from:
|
||||
|
||||
http://landley.net/toybox/bin
|
||||
|
||||
The special name "." indicates the current directory (just like ".." means
|
||||
the parent directory), and you can run a program that isn't in the $PATH by
|
||||
specifying a path to it, so this should work:
|
||||
|
||||
wget http://landley.net/toybox/bin/toybox-x86_64
|
||||
chmod +x toybox-x86_64
|
||||
./toybox-x86_64 echo hello world
|
||||
|
||||
--- Building toybox
|
||||
|
||||
Type "make help" for build instructions.
|
||||
|
||||
Toybox uses the "make menuconfig; make; make install" idiom same as
|
||||
the Linux kernel. Usually you want something like:
|
||||
|
||||
make defconfig
|
||||
make
|
||||
make install
|
||||
|
||||
Or maybe:
|
||||
|
||||
LDFLAGS="--static" CROSS_COMPILE=armv5l- make defconfig toybox
|
||||
PREFIX=/path/to/root/filesystem/bin make install_flat
|
||||
|
||||
The file "configure" defines default values for many environment
|
||||
variables that control the toybox build; if you set a value for any of
|
||||
these, your value is used instead of the default in that file.
|
||||
|
||||
The CROSS_COMPILE argument above is optional, the default builds a version of
|
||||
toybox to run on the current machine. Cross compiling requires an appropriately
|
||||
prefixed cross compiler toolchain, several example toolchains are available at:
|
||||
|
||||
http://landley.net/aboriginal/bin
|
||||
|
||||
For the "CROSS_COMPILE=armv5l-" example above, download
|
||||
cross-compiler-armv5l.tar.bz2, extract it, and add its "bin" subdirectory to
|
||||
your $PATH. (And yes, the trailing - is significant, because the prefix
|
||||
includes a dash.)
|
||||
|
||||
For more about cross compiling, see:
|
||||
|
||||
http://landley.net/writing/docs/cross-compiling.html
|
||||
http://landley.net/aboriginal/architectures.html
|
||||
|
||||
For a more thorough description of the toybox build process, see
|
||||
http://landley.net/toybox/code.html#building
|
||||
|
||||
--- Using toybox
|
||||
|
||||
The toybox build produces a multicall binary, a "swiss-army-knife" program
|
||||
that acts differently depending on the name it was called by (cp, mv, cat...).
|
||||
Installing toybox adds symlinks for each command name to the $PATH.
|
||||
|
||||
The special "toybox" command treats its first argument as the command to run.
|
||||
With no arguments, it lists available commands. This allows you to use toybox
|
||||
without installing it. This is the only command that can have an arbitrary
|
||||
suffix (hence "toybox-armv5l").
|
||||
|
||||
The "help" command provides information about each command (ala "help cat").
|
||||
|
||||
--- Configuring toybox
|
||||
|
||||
It works like the Linux kernel: allnoconfig, defconfig, and menuconfig edit
|
||||
a ".config" file that selects which features to include in the resulting
|
||||
binary. You can save and re-use your .config file, although may want to
|
||||
run "make oldconfig" to re-run the dependency resolver when migrating to
|
||||
new versions.
|
||||
|
||||
The maximum sane configuration is "make defconfig": allyesconfig isn't
|
||||
recommended for toybox because it enables unfinished commands and debug code.
|
||||
|
||||
--- Creating a Toybox-based Linux system
|
||||
|
||||
Toybox is not a complete operating system, it's a program that runs under
|
||||
an operating system. Booting a simple system to a shell prompt requires
|
||||
three packages: an operating system kernel (Linux*) to drive the hardware,
|
||||
one or more programs for the system to run (toybox), and a C library ("libc")
|
||||
to tie them together (toybox has been tested with musl, uClibc, glibc,
|
||||
and bionic).
|
||||
|
||||
The C library is part of a "toolchain", which is an integrated suite
|
||||
of compiler, assembler, and linker, plus the standard headers and libraries
|
||||
necessary to build C programs. (And miscellaneous binaries like nm and objdump.)
|
||||
|
||||
Static linking (with the --static option) copies the shared library contents
|
||||
into the program, resulting in larger but more portable programs, which
|
||||
can run even if they're the only file in the filesystem. Otherwise,
|
||||
the "dynamically" linked programs require the library files to be present on
|
||||
the target system ("man ldd" and "man ld.so" for details).
|
||||
|
||||
An example toybox-based system is Aboriginal Linux:
|
||||
|
||||
http://landley.net/aboriginal/about.html
|
||||
|
||||
That's designed to run under qemu, emulating several different hardware
|
||||
architectures (x86, x86-64, arm, mips, sparc, powerpc, sh4). Each toybox
|
||||
release is regression tested by building Linux From Scratch under this
|
||||
toybox-based system on each supported architecture, using QEMU to emulate
|
||||
big and little endian systems with different word size and alignment
|
||||
requirements. (The eventual goal is to replace Linux From Scratch with
|
||||
the Android Open Source Project.)
|
||||
|
||||
* Or something providing the same API such as FreeBSD's Linux emulation layer.
|
||||
|
||||
--- Presentations
|
||||
|
||||
1) "Why Toybox?" talk at the Embedded Linux Conference in 2013
|
||||
|
||||
video: http://youtu.be/SGmtP5Lg_t0
|
||||
outline: http://landley.net/talks/celf-2013.txt
|
||||
linked from http://landley.net/toybox/ in nav bar on left as "Why is it?"
|
||||
- march 21, 2013 entry has section links.
|
||||
|
||||
2) "Why Public Domain?" The rise and fall of copyleft, Ohio LinuxFest 2013
|
||||
|
||||
audio: https://archive.org/download/OhioLinuxfest2013/24-Rob_Landley-The_Rise_and_Fall_of_Copyleft.mp3
|
||||
outline: http://landley.net/talks/ohio-2013.txt
|
||||
|
||||
3) Why did I do Aboriginal Linux (which led me here)
|
||||
|
||||
260 slide presentation:
|
||||
https://speakerdeck.com/landley/developing-for-non-x86-targets-using-qemu
|
||||
|
||||
How and why to make android self-hosting:
|
||||
http://landley.net/aboriginal/about.html#selfhost
|
||||
|
||||
4) What's new with toybox (ELC 2015 status update):
|
||||
|
||||
video: http://elinux.org/ELC_2015_Presentations
|
||||
outline: http://landley.net/talks/celf-2015.txt
|
||||
|
||||
--- Contributing
|
||||
|
||||
The three important URLs for communicating with the toybox project are:
|
||||
|
||||
web page: http://landley.net/toybox
|
||||
|
||||
mailing list: http://lists.landley.net/listinfo.cgi/toybox-landley.net
|
||||
|
||||
git repo: http://github.com/landley/toybox
|
||||
|
||||
The maintainer prefers patches be sent to the mailing list. If you use git,
|
||||
the easy thing to do is:
|
||||
|
||||
git format-patch -1 $HASH
|
||||
|
||||
Then send a file attachment. The list holds messages from non-subscribers
|
||||
for moderation, but I usually get to them in a day or two.
|
||||
|
||||
Although I do accept pull requests on github, I download the patches and
|
||||
apply them with "git am" (which avoids gratuitous merge commits). Closing
|
||||
the pull request is then the submitter's responsibility.
|
||||
|
||||
If I haven't responded to your patch after one week, feel free to remind
|
||||
me of it.
|
||||
|
||||
Android's policy for toybox patches is that non-build patches should go
|
||||
upstream first (into vanilla toybox, with discussion on the toybox mailing
|
||||
list) and then be pulled into android's toybox repo from there. (They
|
||||
generally resync on fridays). The exception is patches to their build scripts
|
||||
(Android.mk and the checked-in generated/* files) which go directly to AOSP.
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"Name" : "toybox",
|
||||
"License" : "Public Domain",
|
||||
"License File" : "LICENSE",
|
||||
"Version Number" : "0.8.2",
|
||||
"Owner" : "maguangyao@huawei.com",
|
||||
"Upstream URL" : "http://landley.net/toybox",
|
||||
"Description" : "Toybox combines common Linux command line utilities together into a single BSD-licensed executable that's simple, small, fast, reasonably standards-compliant, and powerful enough to turn Android into a development environment."
|
||||
}
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
# third_party_toybox
|
||||
|
||||
#### Description
|
||||
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
|
||||
|
||||
#### Software Architecture
|
||||
Software architecture description
|
||||
|
||||
#### Installation
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Instructions
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Contribution
|
||||
|
||||
1. Fork the repository
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit your code
|
||||
4. Create Pull Request
|
||||
|
||||
|
||||
#### Gitee Feature
|
||||
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
@@ -1,39 +0,0 @@
|
||||
# third_party_toybox
|
||||
|
||||
#### 介绍
|
||||
{**以下是 Gitee 平台说明,您可以替换此简介**
|
||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
|
||||
|
||||
#### 安装教程
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 参与贡献
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
|
||||
|
||||
#### 特技
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This sets environment variables used by scripts/make.sh
|
||||
|
||||
# People run ./configure out of habit, so do "defconfig" for them.
|
||||
|
||||
if [ "$(basename "$0")" == configure ]
|
||||
then
|
||||
echo "Assuming you want 'make defconfig', but you should probably check the README."
|
||||
make defconfig
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# A synonym.
|
||||
[ -z "$CROSS_COMPILE" ] && CROSS_COMPILE="$CROSS"
|
||||
|
||||
# CFLAGS and OPTIMIZE are different so you can add extra CFLAGS without
|
||||
# disabling default optimizations
|
||||
[ -z "$CFLAGS" ] && CFLAGS="-Wall -Wundef -Wno-char-subscripts -Werror=implicit-function-declaration"
|
||||
# Required for our expected ABI. we're 8-bit clean thus "char" must be unsigned.
|
||||
CFLAGS="$CFLAGS -funsigned-char"
|
||||
[ -z "$OPTIMIZE" ] && OPTIMIZE="-Os -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing"
|
||||
# set ASAN=1 to enable "address sanitizer" and debuggable backtraces
|
||||
[ -z "$ASAN" ] || { CFLAGS="$CFLAGS -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address"; NOSTRIP=1; }
|
||||
|
||||
# We accept LDFLAGS, but by default don't have anything in it
|
||||
if [ "$(uname)" != "Darwin" ]
|
||||
then
|
||||
[ -z "$LDOPTIMIZE" ] && LDOPTIMIZE="-Wl,--gc-sections"
|
||||
LDASNEEDED="-Wl,--as-needed"
|
||||
fi
|
||||
|
||||
# The makefile provides defaults for these, so this only gets used if
|
||||
# you call scripts/make.sh and friends directly.
|
||||
|
||||
[ -z "$CC" ] && CC=cc
|
||||
[ -z "$STRIP" ] && STRIP=strip
|
||||
|
||||
# If HOSTCC needs CFLAGS or LDFLAGS, just add them to the variable
|
||||
# ala HOSTCC="blah-cc --static"
|
||||
[ -z "$HOSTCC" ] && HOSTCC=cc
|
||||
|
||||
[ -z "$GENERATED" ] && GENERATED=generated
|
||||
@@ -0,0 +1,644 @@
|
||||
#define CFG_TOYBOX_CONTAINER 1
|
||||
#define USE_TOYBOX_CONTAINER(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_FIFREEZE 1
|
||||
#define USE_TOYBOX_FIFREEZE(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_ICONV 1
|
||||
#define USE_TOYBOX_ICONV(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_FALLOCATE 1
|
||||
#define USE_TOYBOX_FALLOCATE(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_UTMPX 1
|
||||
#define USE_TOYBOX_UTMPX(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_SHADOW 1
|
||||
#define USE_TOYBOX_SHADOW(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_ON_ANDROID 0
|
||||
#define USE_TOYBOX_ON_ANDROID(...)
|
||||
#define CFG_TOYBOX_ANDROID_SCHEDPOLICY 0
|
||||
#define USE_TOYBOX_ANDROID_SCHEDPOLICY(...)
|
||||
#define CFG_TOYBOX_FORK 1
|
||||
#define USE_TOYBOX_FORK(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_PRLIMIT 1
|
||||
#define USE_TOYBOX_PRLIMIT(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_GETRANDOM 0
|
||||
#define USE_TOYBOX_GETRANDOM(...)
|
||||
#define CFG_BASENAME 1
|
||||
#define USE_BASENAME(...) __VA_ARGS__
|
||||
#define CFG_CAL 1
|
||||
#define USE_CAL(...) __VA_ARGS__
|
||||
#define CFG_CAT 1
|
||||
#define USE_CAT(...) __VA_ARGS__
|
||||
#define CFG_CAT_V 0
|
||||
#define USE_CAT_V(...)
|
||||
#define CFG_CATV 1
|
||||
#define USE_CATV(...) __VA_ARGS__
|
||||
#define CFG_CHGRP 1
|
||||
#define USE_CHGRP(...) __VA_ARGS__
|
||||
#define CFG_CHOWN 1
|
||||
#define USE_CHOWN(...) __VA_ARGS__
|
||||
#define CFG_CHMOD 1
|
||||
#define USE_CHMOD(...) __VA_ARGS__
|
||||
#define CFG_CKSUM 1
|
||||
#define USE_CKSUM(...) __VA_ARGS__
|
||||
#define CFG_CRC32 1
|
||||
#define USE_CRC32(...) __VA_ARGS__
|
||||
#define CFG_CMP 1
|
||||
#define USE_CMP(...) __VA_ARGS__
|
||||
#define CFG_COMM 1
|
||||
#define USE_COMM(...) __VA_ARGS__
|
||||
#define CFG_CP 1
|
||||
#define USE_CP(...) __VA_ARGS__
|
||||
#define CFG_CP_PRESERVE 1
|
||||
#define USE_CP_PRESERVE(...) __VA_ARGS__
|
||||
#define CFG_MV 1
|
||||
#define USE_MV(...) __VA_ARGS__
|
||||
#define CFG_INSTALL 1
|
||||
#define USE_INSTALL(...) __VA_ARGS__
|
||||
#define CFG_CPIO 1
|
||||
#define USE_CPIO(...) __VA_ARGS__
|
||||
#define CFG_CUT 1
|
||||
#define USE_CUT(...) __VA_ARGS__
|
||||
#define CFG_DATE 1
|
||||
#define USE_DATE(...) __VA_ARGS__
|
||||
#define CFG_DF 1
|
||||
#define USE_DF(...) __VA_ARGS__
|
||||
#define CFG_DIRNAME 1
|
||||
#define USE_DIRNAME(...) __VA_ARGS__
|
||||
#define CFG_DU 1
|
||||
#define USE_DU(...) __VA_ARGS__
|
||||
#define CFG_ECHO 1
|
||||
#define USE_ECHO(...) __VA_ARGS__
|
||||
#define CFG_ENV 1
|
||||
#define USE_ENV(...) __VA_ARGS__
|
||||
#define CFG_EXPAND 1
|
||||
#define USE_EXPAND(...) __VA_ARGS__
|
||||
#define CFG_FALSE 1
|
||||
#define USE_FALSE(...) __VA_ARGS__
|
||||
#define CFG_FILE 1
|
||||
#define USE_FILE(...) __VA_ARGS__
|
||||
#define CFG_FIND 1
|
||||
#define USE_FIND(...) __VA_ARGS__
|
||||
#define CFG_GETCONF 1
|
||||
#define USE_GETCONF(...) __VA_ARGS__
|
||||
#define CFG_GREP 1
|
||||
#define USE_GREP(...) __VA_ARGS__
|
||||
#define CFG_EGREP 1
|
||||
#define USE_EGREP(...) __VA_ARGS__
|
||||
#define CFG_FGREP 1
|
||||
#define USE_FGREP(...) __VA_ARGS__
|
||||
#define CFG_HEAD 1
|
||||
#define USE_HEAD(...) __VA_ARGS__
|
||||
#define CFG_ICONV 1
|
||||
#define USE_ICONV(...) __VA_ARGS__
|
||||
#define CFG_ID 1
|
||||
#define USE_ID(...) __VA_ARGS__
|
||||
#define CFG_ID_Z 0
|
||||
#define USE_ID_Z(...)
|
||||
#define CFG_GROUPS 1
|
||||
#define USE_GROUPS(...) __VA_ARGS__
|
||||
#define CFG_LOGNAME 1
|
||||
#define USE_LOGNAME(...) __VA_ARGS__
|
||||
#define CFG_WHOAMI 1
|
||||
#define USE_WHOAMI(...) __VA_ARGS__
|
||||
#define CFG_KILL 1
|
||||
#define USE_KILL(...) __VA_ARGS__
|
||||
#define CFG_KILLALL5 1
|
||||
#define USE_KILLALL5(...) __VA_ARGS__
|
||||
#define CFG_LINK 1
|
||||
#define USE_LINK(...) __VA_ARGS__
|
||||
#define CFG_LN 1
|
||||
#define USE_LN(...) __VA_ARGS__
|
||||
#define CFG_LOGGER 1
|
||||
#define USE_LOGGER(...) __VA_ARGS__
|
||||
#define CFG_LS 1
|
||||
#define USE_LS(...) __VA_ARGS__
|
||||
#define CFG_MKDIR 1
|
||||
#define USE_MKDIR(...) __VA_ARGS__
|
||||
#define CFG_MKDIR_Z 0
|
||||
#define USE_MKDIR_Z(...)
|
||||
#define CFG_MKFIFO 1
|
||||
#define USE_MKFIFO(...) __VA_ARGS__
|
||||
#define CFG_MKFIFO_Z 0
|
||||
#define USE_MKFIFO_Z(...)
|
||||
#define CFG_NICE 1
|
||||
#define USE_NICE(...) __VA_ARGS__
|
||||
#define CFG_NL 1
|
||||
#define USE_NL(...) __VA_ARGS__
|
||||
#define CFG_NOHUP 1
|
||||
#define USE_NOHUP(...) __VA_ARGS__
|
||||
#define CFG_OD 1
|
||||
#define USE_OD(...) __VA_ARGS__
|
||||
#define CFG_PASTE 1
|
||||
#define USE_PASTE(...) __VA_ARGS__
|
||||
#define CFG_PATCH 1
|
||||
#define USE_PATCH(...) __VA_ARGS__
|
||||
#define CFG_PRINTF 1
|
||||
#define USE_PRINTF(...) __VA_ARGS__
|
||||
#define CFG_PS 1
|
||||
#define USE_PS(...) __VA_ARGS__
|
||||
#define CFG_TOP 1
|
||||
#define USE_TOP(...) __VA_ARGS__
|
||||
#define CFG_IOTOP 1
|
||||
#define USE_IOTOP(...) __VA_ARGS__
|
||||
#define CFG_PGREP 1
|
||||
#define USE_PGREP(...) __VA_ARGS__
|
||||
#define CFG_PKILL 1
|
||||
#define USE_PKILL(...) __VA_ARGS__
|
||||
#define CFG_PWD 1
|
||||
#define USE_PWD(...) __VA_ARGS__
|
||||
#define CFG_RENICE 1
|
||||
#define USE_RENICE(...) __VA_ARGS__
|
||||
#define CFG_RM 1
|
||||
#define USE_RM(...) __VA_ARGS__
|
||||
#define CFG_RMDIR 1
|
||||
#define USE_RMDIR(...) __VA_ARGS__
|
||||
#define CFG_SED 1
|
||||
#define USE_SED(...) __VA_ARGS__
|
||||
#define CFG_SLEEP 1
|
||||
#define USE_SLEEP(...) __VA_ARGS__
|
||||
#define CFG_SORT 1
|
||||
#define USE_SORT(...) __VA_ARGS__
|
||||
#define CFG_SORT_FLOAT 1
|
||||
#define USE_SORT_FLOAT(...) __VA_ARGS__
|
||||
#define CFG_SPLIT 1
|
||||
#define USE_SPLIT(...) __VA_ARGS__
|
||||
#define CFG_STRINGS 1
|
||||
#define USE_STRINGS(...) __VA_ARGS__
|
||||
#define CFG_TAIL 1
|
||||
#define USE_TAIL(...) __VA_ARGS__
|
||||
#define CFG_TAR 1
|
||||
#define USE_TAR(...) __VA_ARGS__
|
||||
#define CFG_TEE 1
|
||||
#define USE_TEE(...) __VA_ARGS__
|
||||
#define CFG_TEST 1
|
||||
#define USE_TEST(...) __VA_ARGS__
|
||||
#define CFG_TIME 1
|
||||
#define USE_TIME(...) __VA_ARGS__
|
||||
#define CFG_TOUCH 1
|
||||
#define USE_TOUCH(...) __VA_ARGS__
|
||||
#define CFG_TRUE 1
|
||||
#define USE_TRUE(...) __VA_ARGS__
|
||||
#define CFG_TTY 1
|
||||
#define USE_TTY(...) __VA_ARGS__
|
||||
#define CFG_ULIMIT 1
|
||||
#define USE_ULIMIT(...) __VA_ARGS__
|
||||
#define CFG_ARCH 1
|
||||
#define USE_ARCH(...) __VA_ARGS__
|
||||
#define CFG_UNAME 1
|
||||
#define USE_UNAME(...) __VA_ARGS__
|
||||
#define CFG_UNIQ 1
|
||||
#define USE_UNIQ(...) __VA_ARGS__
|
||||
#define CFG_UNLINK 1
|
||||
#define USE_UNLINK(...) __VA_ARGS__
|
||||
#define CFG_UUDECODE 1
|
||||
#define USE_UUDECODE(...) __VA_ARGS__
|
||||
#define CFG_UUENCODE 1
|
||||
#define USE_UUENCODE(...) __VA_ARGS__
|
||||
#define CFG_WC 1
|
||||
#define USE_WC(...) __VA_ARGS__
|
||||
#define CFG_WHO 1
|
||||
#define USE_WHO(...) __VA_ARGS__
|
||||
#define CFG_XARGS 1
|
||||
#define USE_XARGS(...) __VA_ARGS__
|
||||
#define CFG_ARP 0
|
||||
#define USE_ARP(...)
|
||||
#define CFG_ARPING 0
|
||||
#define USE_ARPING(...)
|
||||
#define CFG_BC 0
|
||||
#define USE_BC(...)
|
||||
#define CFG_BOOTCHARTD 1
|
||||
#define USE_BOOTCHARTD(...) __VA_ARGS__
|
||||
#define CFG_BRCTL 0
|
||||
#define USE_BRCTL(...)
|
||||
#define CFG_CROND 0
|
||||
#define USE_CROND(...)
|
||||
#define CFG_CRONTAB 0
|
||||
#define USE_CRONTAB(...)
|
||||
#define CFG_DD 0
|
||||
#define USE_DD(...)
|
||||
#define CFG_DHCP6 0
|
||||
#define USE_DHCP6(...)
|
||||
#define CFG_DHCP 0
|
||||
#define USE_DHCP(...)
|
||||
#define CFG_DHCPD 0
|
||||
#define USE_DHCPD(...)
|
||||
#define CFG_DEBUG_DHCP 0
|
||||
#define USE_DEBUG_DHCP(...)
|
||||
#define CFG_DIFF 1
|
||||
#define USE_DIFF(...) __VA_ARGS__
|
||||
#define CFG_DUMPLEASES 0
|
||||
#define USE_DUMPLEASES(...)
|
||||
#define CFG_EXPR 0
|
||||
#define USE_EXPR(...)
|
||||
#define CFG_FDISK 0
|
||||
#define USE_FDISK(...)
|
||||
#define CFG_FOLD 0
|
||||
#define USE_FOLD(...)
|
||||
#define CFG_FSCK 0
|
||||
#define USE_FSCK(...)
|
||||
#define CFG_GETFATTR 0
|
||||
#define USE_GETFATTR(...)
|
||||
#define CFG_GETTY 1
|
||||
#define USE_GETTY(...) __VA_ARGS__
|
||||
#define CFG_GROUPADD 0
|
||||
#define USE_GROUPADD(...)
|
||||
#define CFG_GROUPDEL 0
|
||||
#define USE_GROUPDEL(...)
|
||||
#define CFG_HOST 0
|
||||
#define USE_HOST(...)
|
||||
#define CFG_INIT 0
|
||||
#define USE_INIT(...)
|
||||
#define CFG_IP 0
|
||||
#define USE_IP(...)
|
||||
#define CFG_IPCRM 0
|
||||
#define USE_IPCRM(...)
|
||||
#define CFG_IPCS 0
|
||||
#define USE_IPCS(...)
|
||||
#define CFG_KLOGD 0
|
||||
#define USE_KLOGD(...)
|
||||
#define CFG_KLOGD_SOURCE_RING_BUFFER 0
|
||||
#define USE_KLOGD_SOURCE_RING_BUFFER(...)
|
||||
#define CFG_LAST 0
|
||||
#define USE_LAST(...)
|
||||
#define CFG_LSOF 0
|
||||
#define USE_LSOF(...)
|
||||
#define CFG_MAN 0
|
||||
#define USE_MAN(...)
|
||||
#define CFG_MDEV 0
|
||||
#define USE_MDEV(...)
|
||||
#define CFG_MDEV_CONF 0
|
||||
#define USE_MDEV_CONF(...)
|
||||
#define CFG_MKE2FS 0
|
||||
#define USE_MKE2FS(...)
|
||||
#define CFG_MKE2FS_JOURNAL 0
|
||||
#define USE_MKE2FS_JOURNAL(...)
|
||||
#define CFG_MKE2FS_GEN 0
|
||||
#define USE_MKE2FS_GEN(...)
|
||||
#define CFG_MKE2FS_LABEL 0
|
||||
#define USE_MKE2FS_LABEL(...)
|
||||
#define CFG_MKE2FS_EXTENDED 0
|
||||
#define USE_MKE2FS_EXTENDED(...)
|
||||
#define CFG_MODPROBE 0
|
||||
#define USE_MODPROBE(...)
|
||||
#define CFG_MORE 1
|
||||
#define USE_MORE(...) __VA_ARGS__
|
||||
#define CFG_OPENVT 0
|
||||
#define USE_OPENVT(...)
|
||||
#define CFG_DEALLOCVT 0
|
||||
#define USE_DEALLOCVT(...)
|
||||
#define CFG_ROUTE 0
|
||||
#define USE_ROUTE(...)
|
||||
#define CFG_SH 0
|
||||
#define USE_SH(...)
|
||||
#define CFG_CD 0
|
||||
#define USE_CD(...)
|
||||
#define CFG_EXIT 0
|
||||
#define USE_EXIT(...)
|
||||
#define CFG_STTY 0
|
||||
#define USE_STTY(...)
|
||||
#define CFG_SULOGIN 0
|
||||
#define USE_SULOGIN(...)
|
||||
#define CFG_SYSLOGD 0
|
||||
#define USE_SYSLOGD(...)
|
||||
#define CFG_TCPSVD 0
|
||||
#define USE_TCPSVD(...)
|
||||
#define CFG_TELNET 0
|
||||
#define USE_TELNET(...)
|
||||
#define CFG_TELNETD 0
|
||||
#define USE_TELNETD(...)
|
||||
#define CFG_TFTP 0
|
||||
#define USE_TFTP(...)
|
||||
#define CFG_TFTPD 0
|
||||
#define USE_TFTPD(...)
|
||||
#define CFG_TRACEROUTE 0
|
||||
#define USE_TRACEROUTE(...)
|
||||
#define CFG_TR 0
|
||||
#define USE_TR(...)
|
||||
#define CFG_USERADD 0
|
||||
#define USE_USERADD(...)
|
||||
#define CFG_USERDEL 0
|
||||
#define USE_USERDEL(...)
|
||||
#define CFG_VI 0
|
||||
#define USE_VI(...)
|
||||
#define CFG_WGET 0
|
||||
#define USE_WGET(...)
|
||||
#define CFG_XZCAT 0
|
||||
#define USE_XZCAT(...)
|
||||
#define CFG_ACPI 1
|
||||
#define USE_ACPI(...) __VA_ARGS__
|
||||
#define CFG_ASCII 1
|
||||
#define USE_ASCII(...) __VA_ARGS__
|
||||
#define CFG_BASE64 1
|
||||
#define USE_BASE64(...) __VA_ARGS__
|
||||
#define CFG_BLKID 1
|
||||
#define USE_BLKID(...) __VA_ARGS__
|
||||
#define CFG_FSTYPE 1
|
||||
#define USE_FSTYPE(...) __VA_ARGS__
|
||||
#define CFG_BLOCKDEV 1
|
||||
#define USE_BLOCKDEV(...) __VA_ARGS__
|
||||
#define CFG_BUNZIP2 1
|
||||
#define USE_BUNZIP2(...) __VA_ARGS__
|
||||
#define CFG_BZCAT 1
|
||||
#define USE_BZCAT(...) __VA_ARGS__
|
||||
#define CFG_CHCON 0
|
||||
#define USE_CHCON(...)
|
||||
#define CFG_CHROOT 1
|
||||
#define USE_CHROOT(...) __VA_ARGS__
|
||||
#define CFG_CHRT 1
|
||||
#define USE_CHRT(...) __VA_ARGS__
|
||||
#define CFG_CHVT 1
|
||||
#define USE_CHVT(...) __VA_ARGS__
|
||||
#define CFG_CLEAR 1
|
||||
#define USE_CLEAR(...) __VA_ARGS__
|
||||
#define CFG_COUNT 1
|
||||
#define USE_COUNT(...) __VA_ARGS__
|
||||
#define CFG_DEVMEM 1
|
||||
#define USE_DEVMEM(...) __VA_ARGS__
|
||||
#define CFG_DOS2UNIX 1
|
||||
#define USE_DOS2UNIX(...) __VA_ARGS__
|
||||
#define CFG_UNIX2DOS 1
|
||||
#define USE_UNIX2DOS(...) __VA_ARGS__
|
||||
#define CFG_EJECT 1
|
||||
#define USE_EJECT(...) __VA_ARGS__
|
||||
#define CFG_FACTOR 1
|
||||
#define USE_FACTOR(...) __VA_ARGS__
|
||||
#define CFG_FALLOCATE 1
|
||||
#define USE_FALLOCATE(...) __VA_ARGS__
|
||||
#define CFG_FLOCK 1
|
||||
#define USE_FLOCK(...) __VA_ARGS__
|
||||
#define CFG_FMT 1
|
||||
#define USE_FMT(...) __VA_ARGS__
|
||||
#define CFG_FREE 1
|
||||
#define USE_FREE(...) __VA_ARGS__
|
||||
#define CFG_FREERAMDISK 1
|
||||
#define USE_FREERAMDISK(...) __VA_ARGS__
|
||||
#define CFG_FSFREEZE 1
|
||||
#define USE_FSFREEZE(...) __VA_ARGS__
|
||||
#define CFG_FSYNC 1
|
||||
#define USE_FSYNC(...) __VA_ARGS__
|
||||
#define CFG_HELP 1
|
||||
#define USE_HELP(...) __VA_ARGS__
|
||||
#define CFG_HELP_EXTRAS 1
|
||||
#define USE_HELP_EXTRAS(...) __VA_ARGS__
|
||||
#define CFG_HEXEDIT 1
|
||||
#define USE_HEXEDIT(...) __VA_ARGS__
|
||||
#define CFG_HWCLOCK 1
|
||||
#define USE_HWCLOCK(...) __VA_ARGS__
|
||||
#define CFG_I2CDETECT 1
|
||||
#define USE_I2CDETECT(...) __VA_ARGS__
|
||||
#define CFG_I2CDUMP 1
|
||||
#define USE_I2CDUMP(...) __VA_ARGS__
|
||||
#define CFG_I2CGET 1
|
||||
#define USE_I2CGET(...) __VA_ARGS__
|
||||
#define CFG_I2CSET 1
|
||||
#define USE_I2CSET(...) __VA_ARGS__
|
||||
#define CFG_INOTIFYD 1
|
||||
#define USE_INOTIFYD(...) __VA_ARGS__
|
||||
#define CFG_INSMOD 1
|
||||
#define USE_INSMOD(...) __VA_ARGS__
|
||||
#define CFG_IONICE 1
|
||||
#define USE_IONICE(...) __VA_ARGS__
|
||||
#define CFG_IORENICE 1
|
||||
#define USE_IORENICE(...) __VA_ARGS__
|
||||
#define CFG_LOGIN 1
|
||||
#define USE_LOGIN(...) __VA_ARGS__
|
||||
#define CFG_LOSETUP 1
|
||||
#define USE_LOSETUP(...) __VA_ARGS__
|
||||
#define CFG_LSATTR 1
|
||||
#define USE_LSATTR(...) __VA_ARGS__
|
||||
#define CFG_CHATTR 1
|
||||
#define USE_CHATTR(...) __VA_ARGS__
|
||||
#define CFG_LSMOD 1
|
||||
#define USE_LSMOD(...) __VA_ARGS__
|
||||
#define CFG_LSPCI 1
|
||||
#define USE_LSPCI(...) __VA_ARGS__
|
||||
#define CFG_LSPCI_TEXT 1
|
||||
#define USE_LSPCI_TEXT(...) __VA_ARGS__
|
||||
#define CFG_LSUSB 1
|
||||
#define USE_LSUSB(...) __VA_ARGS__
|
||||
#define CFG_MAKEDEVS 1
|
||||
#define USE_MAKEDEVS(...) __VA_ARGS__
|
||||
#define CFG_MCOOKIE 1
|
||||
#define USE_MCOOKIE(...) __VA_ARGS__
|
||||
#define CFG_MIX 1
|
||||
#define USE_MIX(...) __VA_ARGS__
|
||||
#define CFG_MKPASSWD 1
|
||||
#define USE_MKPASSWD(...) __VA_ARGS__
|
||||
#define CFG_MKSWAP 1
|
||||
#define USE_MKSWAP(...) __VA_ARGS__
|
||||
#define CFG_MODINFO 1
|
||||
#define USE_MODINFO(...) __VA_ARGS__
|
||||
#define CFG_MOUNTPOINT 1
|
||||
#define USE_MOUNTPOINT(...) __VA_ARGS__
|
||||
#define CFG_NBD_CLIENT 1
|
||||
#define USE_NBD_CLIENT(...) __VA_ARGS__
|
||||
#define CFG_UNSHARE 1
|
||||
#define USE_UNSHARE(...) __VA_ARGS__
|
||||
#define CFG_NSENTER 1
|
||||
#define USE_NSENTER(...) __VA_ARGS__
|
||||
#define CFG_ONEIT 1
|
||||
#define USE_ONEIT(...) __VA_ARGS__
|
||||
#define CFG_PARTPROBE 1
|
||||
#define USE_PARTPROBE(...) __VA_ARGS__
|
||||
#define CFG_PIVOT_ROOT 1
|
||||
#define USE_PIVOT_ROOT(...) __VA_ARGS__
|
||||
#define CFG_PMAP 1
|
||||
#define USE_PMAP(...) __VA_ARGS__
|
||||
#define CFG_PRINTENV 1
|
||||
#define USE_PRINTENV(...) __VA_ARGS__
|
||||
#define CFG_PWDX 1
|
||||
#define USE_PWDX(...) __VA_ARGS__
|
||||
#define CFG_READAHEAD 1
|
||||
#define USE_READAHEAD(...) __VA_ARGS__
|
||||
#define CFG_READLINK 1
|
||||
#define USE_READLINK(...) __VA_ARGS__
|
||||
#define CFG_REALPATH 1
|
||||
#define USE_REALPATH(...) __VA_ARGS__
|
||||
#define CFG_REBOOT 1
|
||||
#define USE_REBOOT(...) __VA_ARGS__
|
||||
#define CFG_RESET 1
|
||||
#define USE_RESET(...) __VA_ARGS__
|
||||
#define CFG_REV 1
|
||||
#define USE_REV(...) __VA_ARGS__
|
||||
#define CFG_RMMOD 1
|
||||
#define USE_RMMOD(...) __VA_ARGS__
|
||||
#define CFG_SETFATTR 1
|
||||
#define USE_SETFATTR(...) __VA_ARGS__
|
||||
#define CFG_SETSID 1
|
||||
#define USE_SETSID(...) __VA_ARGS__
|
||||
#define CFG_SHRED 1
|
||||
#define USE_SHRED(...) __VA_ARGS__
|
||||
#define CFG_STAT 1
|
||||
#define USE_STAT(...) __VA_ARGS__
|
||||
#define CFG_SWAPOFF 1
|
||||
#define USE_SWAPOFF(...) __VA_ARGS__
|
||||
#define CFG_SWAPON 1
|
||||
#define USE_SWAPON(...) __VA_ARGS__
|
||||
#define CFG_SWITCH_ROOT 1
|
||||
#define USE_SWITCH_ROOT(...) __VA_ARGS__
|
||||
#define CFG_SYSCTL 1
|
||||
#define USE_SYSCTL(...) __VA_ARGS__
|
||||
#define CFG_TAC 1
|
||||
#define USE_TAC(...) __VA_ARGS__
|
||||
#define CFG_NPROC 1
|
||||
#define USE_NPROC(...) __VA_ARGS__
|
||||
#define CFG_TASKSET 1
|
||||
#define USE_TASKSET(...) __VA_ARGS__
|
||||
#define CFG_TIMEOUT 1
|
||||
#define USE_TIMEOUT(...) __VA_ARGS__
|
||||
#define CFG_TRUNCATE 1
|
||||
#define USE_TRUNCATE(...) __VA_ARGS__
|
||||
#define CFG_UPTIME 1
|
||||
#define USE_UPTIME(...) __VA_ARGS__
|
||||
#define CFG_USLEEP 1
|
||||
#define USE_USLEEP(...) __VA_ARGS__
|
||||
#define CFG_UUIDGEN 1
|
||||
#define USE_UUIDGEN(...) __VA_ARGS__
|
||||
#define CFG_VCONFIG 1
|
||||
#define USE_VCONFIG(...) __VA_ARGS__
|
||||
#define CFG_VMSTAT 1
|
||||
#define USE_VMSTAT(...) __VA_ARGS__
|
||||
#define CFG_WATCH 1
|
||||
#define USE_WATCH(...) __VA_ARGS__
|
||||
#define CFG_W 1
|
||||
#define USE_W(...) __VA_ARGS__
|
||||
#define CFG_WHICH 1
|
||||
#define USE_WHICH(...) __VA_ARGS__
|
||||
#define CFG_XXD 1
|
||||
#define USE_XXD(...) __VA_ARGS__
|
||||
#define CFG_YES 1
|
||||
#define USE_YES(...) __VA_ARGS__
|
||||
#define CFG_FTPGET 1
|
||||
#define USE_FTPGET(...) __VA_ARGS__
|
||||
#define CFG_FTPPUT 1
|
||||
#define USE_FTPPUT(...) __VA_ARGS__
|
||||
#define CFG_IFCONFIG 1
|
||||
#define USE_IFCONFIG(...) __VA_ARGS__
|
||||
#define CFG_MICROCOM 1
|
||||
#define USE_MICROCOM(...) __VA_ARGS__
|
||||
#define CFG_NETCAT 1
|
||||
#define USE_NETCAT(...) __VA_ARGS__
|
||||
#define CFG_NETCAT_LISTEN 1
|
||||
#define USE_NETCAT_LISTEN(...) __VA_ARGS__
|
||||
#define CFG_NETSTAT 1
|
||||
#define USE_NETSTAT(...) __VA_ARGS__
|
||||
#define CFG_PING 1
|
||||
#define USE_PING(...) __VA_ARGS__
|
||||
#define CFG_RFKILL 1
|
||||
#define USE_RFKILL(...) __VA_ARGS__
|
||||
#define CFG_SNTP 1
|
||||
#define USE_SNTP(...) __VA_ARGS__
|
||||
#define CFG_TUNCTL 1
|
||||
#define USE_TUNCTL(...) __VA_ARGS__
|
||||
#define CFG_DMESG 1
|
||||
#define USE_DMESG(...) __VA_ARGS__
|
||||
#define CFG_GZIP 0
|
||||
#define USE_GZIP(...)
|
||||
#define CFG_GUNZIP 1
|
||||
#define USE_GUNZIP(...) __VA_ARGS__
|
||||
#define CFG_ZCAT 1
|
||||
#define USE_ZCAT(...) __VA_ARGS__
|
||||
#define CFG_HOSTNAME 1
|
||||
#define USE_HOSTNAME(...) __VA_ARGS__
|
||||
#define CFG_DNSDOMAINNAME 1
|
||||
#define USE_DNSDOMAINNAME(...) __VA_ARGS__
|
||||
#define CFG_KILLALL 1
|
||||
#define USE_KILLALL(...) __VA_ARGS__
|
||||
#define CFG_MD5SUM 1
|
||||
#define USE_MD5SUM(...) __VA_ARGS__
|
||||
#define CFG_SHA1SUM 1
|
||||
#define USE_SHA1SUM(...) __VA_ARGS__
|
||||
#define CFG_SHA224SUM 0
|
||||
#define USE_SHA224SUM(...)
|
||||
#define CFG_SHA256SUM 0
|
||||
#define USE_SHA256SUM(...)
|
||||
#define CFG_SHA384SUM 0
|
||||
#define USE_SHA384SUM(...)
|
||||
#define CFG_SHA512SUM 0
|
||||
#define USE_SHA512SUM(...)
|
||||
#define CFG_MKNOD 1
|
||||
#define USE_MKNOD(...) __VA_ARGS__
|
||||
#define CFG_MKNOD_Z 0
|
||||
#define USE_MKNOD_Z(...)
|
||||
#define CFG_MKTEMP 1
|
||||
#define USE_MKTEMP(...) __VA_ARGS__
|
||||
#define CFG_MOUNT 1
|
||||
#define USE_MOUNT(...) __VA_ARGS__
|
||||
#define CFG_PASSWD 1
|
||||
#define USE_PASSWD(...) __VA_ARGS__
|
||||
#define CFG_PASSWD_SAD 0
|
||||
#define USE_PASSWD_SAD(...)
|
||||
#define CFG_PIDOF 1
|
||||
#define USE_PIDOF(...) __VA_ARGS__
|
||||
#define CFG_SEQ 1
|
||||
#define USE_SEQ(...) __VA_ARGS__
|
||||
#define CFG_SU 1
|
||||
#define USE_SU(...) __VA_ARGS__
|
||||
#define CFG_SYNC 1
|
||||
#define USE_SYNC(...) __VA_ARGS__
|
||||
#define CFG_UMOUNT 1
|
||||
#define USE_UMOUNT(...) __VA_ARGS__
|
||||
#define CFG_DEMO_MANY_OPTIONS 0
|
||||
#define USE_DEMO_MANY_OPTIONS(...)
|
||||
#define CFG_DEMO_NUMBER 0
|
||||
#define USE_DEMO_NUMBER(...)
|
||||
#define CFG_DEMO_SCANKEY 0
|
||||
#define USE_DEMO_SCANKEY(...)
|
||||
#define CFG_DEMO_UTF8TOWC 0
|
||||
#define USE_DEMO_UTF8TOWC(...)
|
||||
#define CFG_HELLO 0
|
||||
#define USE_HELLO(...)
|
||||
#define CFG_HOSTID 0
|
||||
#define USE_HOSTID(...)
|
||||
#define CFG_LOGWRAPPER 0
|
||||
#define USE_LOGWRAPPER(...)
|
||||
#define CFG_SKELETON 0
|
||||
#define USE_SKELETON(...)
|
||||
#define CFG_SKELETON_ALIAS 0
|
||||
#define USE_SKELETON_ALIAS(...)
|
||||
#define CFG_GETENFORCE 0
|
||||
#define USE_GETENFORCE(...)
|
||||
#define CFG_LOAD_POLICY 0
|
||||
#define USE_LOAD_POLICY(...)
|
||||
#define CFG_LOG 0
|
||||
#define USE_LOG(...)
|
||||
#define CFG_RESTORECON 0
|
||||
#define USE_RESTORECON(...)
|
||||
#define CFG_RUNCON 0
|
||||
#define USE_RUNCON(...)
|
||||
#define CFG_SENDEVENT 0
|
||||
#define USE_SENDEVENT(...)
|
||||
#define CFG_SETENFORCE 0
|
||||
#define USE_SETENFORCE(...)
|
||||
#define CFG_TOYBOX 1
|
||||
#define USE_TOYBOX(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_SUID 1
|
||||
#define USE_TOYBOX_SUID(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_LSM_NONE 1
|
||||
#define USE_TOYBOX_LSM_NONE(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_SELINUX 0
|
||||
#define USE_TOYBOX_SELINUX(...)
|
||||
#define CFG_TOYBOX_SMACK 0
|
||||
#define USE_TOYBOX_SMACK(...)
|
||||
#define CFG_TOYBOX_LIBCRYPTO 0
|
||||
#define USE_TOYBOX_LIBCRYPTO(...)
|
||||
#define CFG_TOYBOX_LIBZ 0
|
||||
#define USE_TOYBOX_LIBZ(...)
|
||||
#define CFG_TOYBOX_FLOAT 1
|
||||
#define USE_TOYBOX_FLOAT(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_HELP 1
|
||||
#define USE_TOYBOX_HELP(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_HELP_DASHDASH 1
|
||||
#define USE_TOYBOX_HELP_DASHDASH(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_I18N 1
|
||||
#define USE_TOYBOX_I18N(...) __VA_ARGS__
|
||||
#define CFG_TOYBOX_FREE 0
|
||||
#define USE_TOYBOX_FREE(...)
|
||||
#define CFG_TOYBOX_NORECURSE 0
|
||||
#define USE_TOYBOX_NORECURSE(...)
|
||||
#define CFG_TOYBOX_DEBUG 0
|
||||
#define USE_TOYBOX_DEBUG(...)
|
||||
#define CFG_TOYBOX_PEDANTIC_ARGS 0
|
||||
#define USE_TOYBOX_PEDANTIC_ARGS(...)
|
||||
#define CFG_TOYBOX_UID_SYS 100
|
||||
#define CFG_TOYBOX_UID_USR 500
|
||||
#define CFG_TOYBOX_MUSL_NOMMU_IS_BROKEN 0
|
||||
#define USE_TOYBOX_MUSL_NOMMU_IS_BROKEN(...)
|
||||
+6198
File diff suppressed because it is too large
Load Diff
+1576
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,301 @@
|
||||
USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))
|
||||
USE_SH(OLDTOY(-bash, sh, 0))
|
||||
USE_SH(OLDTOY(-sh, sh, 0))
|
||||
USE_SH(OLDTOY(-toysh, sh, 0))
|
||||
USE_TRUE(OLDTOY(:, true, TOYFLAG_NOFORK|TOYFLAG_NOHELP))
|
||||
USE_TEST(OLDTOY([, test, TOYFLAG_NOFORK|TOYFLAG_NOHELP))
|
||||
USE_ACPI(NEWTOY(acpi, "abctV", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GROUPADD(OLDTOY(addgroup, groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_USERADD(OLDTOY(adduser, useradd, TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
|
||||
USE_ARCH(NEWTOY(arch, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_ASCII(NEWTOY(ascii, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_BASE64(NEWTOY(base64, "diw#<0=76[!dw]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_BASENAME(NEWTOY(basename, "^<1as:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN))
|
||||
USE_BC(NEWTOY(bc, "i(interactive)l(mathlib)q(quiet)s(standard)w(warn)", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_BLKID(NEWTOY(blkid, "ULs*[!LU]", TOYFLAG_BIN))
|
||||
USE_BLOCKDEV(NEWTOY(blockdev, "<1>1(setro)(setrw)(getro)(getss)(getbsz)(setbsz)#<0(getsz)(getsize)(getsize64)(getra)(setra)#<0(flushbufs)(rereadpt)",TOYFLAG_SBIN))
|
||||
USE_BOOTCHARTD(NEWTOY(bootchartd, 0, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_BUNZIP2(NEWTOY(bunzip2, "cftkv", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CAT(NEWTOY(cat, "u"USE_CAT_V("vte"), TOYFLAG_BIN))
|
||||
USE_CATV(NEWTOY(catv, USE_CATV("vte"), TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK))
|
||||
USE_CHATTR(NEWTOY(chattr, NULL, TOYFLAG_BIN))
|
||||
USE_CHCON(NEWTOY(chcon, "<2hvR", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv[-HLP]", TOYFLAG_BIN))
|
||||
USE_CHMOD(NEWTOY(chmod, "<2?vRf[-vf]", TOYFLAG_BIN))
|
||||
USE_CHOWN(OLDTOY(chown, chgrp, TOYFLAG_BIN))
|
||||
USE_CHROOT(NEWTOY(chroot, "^<1", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_ARGFAIL(125)))
|
||||
USE_CHRT(NEWTOY(chrt, "^mp#<0iRbrfo[!ibrfo]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CKSUM(NEWTOY(cksum, "HIPLN", TOYFLAG_BIN))
|
||||
USE_CLEAR(NEWTOY(clear, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CMP(NEWTOY(cmp, "<1>2ls(silent)(quiet)[!ls]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"D(parents)RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]", TOYFLAG_BIN))
|
||||
USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
|
||||
USE_CRC32(NEWTOY(crc32, 0, TOYFLAG_BIN))
|
||||
USE_CROND(NEWTOY(crond, "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_CRONTAB(NEWTOY(crontab, "c:u:elr[!elr]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
USE_CUT(NEWTOY(cut, "b*|c*|f*|F*|C*|O(output-delimiter):d:sDn[!cbf]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DATE(NEWTOY(date, "d:D:r:u[!dr]", TOYFLAG_BIN))
|
||||
USE_DD(NEWTOY(dd, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
|
||||
USE_GROUPDEL(OLDTOY(delgroup, groupdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_USERDEL(OLDTOY(deluser, userdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_DEMO_MANY_OPTIONS(NEWTOY(demo_many_options, "ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba", TOYFLAG_BIN))
|
||||
USE_DEMO_NUMBER(NEWTOY(demo_number, "D#=3<3hdbs", TOYFLAG_BIN))
|
||||
USE_DEMO_SCANKEY(NEWTOY(demo_scankey, 0, TOYFLAG_BIN))
|
||||
USE_DEMO_UTF8TOWC(NEWTOY(demo_utf8towc, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DEVMEM(NEWTOY(devmem, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DF(NEWTOY(df, "HPkhit*a[-HPkh]", TOYFLAG_SBIN))
|
||||
USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
|
||||
USE_DHCP6(NEWTOY(dhcp6, "r:A#<0T#<0t#<0s:p:i:SRvqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
|
||||
USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
|
||||
USE_DIFF(NEWTOY(diff, "<2>2(color)(strip-trailing-cr)B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]", TOYFLAG_BIN))
|
||||
USE_DNSDOMAINNAME(NEWTOY(dnsdomainname, ">0", TOYFLAG_BIN))
|
||||
USE_DOS2UNIX(NEWTOY(dos2unix, 0, TOYFLAG_BIN))
|
||||
USE_DU(NEWTOY(du, "d#<0=-1hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_DUMPLEASES(NEWTOY(dumpleases, ">0arf:[!ar]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ECHO(NEWTOY(echo, "^?Een[-eE]", TOYFLAG_BIN|TOYFLAG_MAYFORK))
|
||||
USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_EJECT(NEWTOY(eject, ">1stT[!tT]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ENV(NEWTOY(env, "^0iu*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125)))
|
||||
USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK))
|
||||
USE_EXPAND(NEWTOY(expand, "t*", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FACTOR(NEWTOY(factor, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FALLOCATE(NEWTOY(fallocate, ">1l#|o#", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
|
||||
USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
|
||||
USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_FILE(NEWTOY(file, "<1bhLs[!hL]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FLOCK(NEWTOY(flock, "<1>1nsux[-sux]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FMT(NEWTOY(fmt, "w#<0=75", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_FOLD(NEWTOY(fold, "bsuw#<1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FREE(NEWTOY(free, "htgmkb[!htgmkb]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FREERAMDISK(NEWTOY(freeramdisk, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_FSCK(NEWTOY(fsck, "?t:ANPRTVsC#", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FSFREEZE(NEWTOY(fsfreeze, "<1>1f|u|[!fu]", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_FSTYPE(NEWTOY(fstype, "<1", TOYFLAG_BIN))
|
||||
USE_FSYNC(NEWTOY(fsync, "<1d", TOYFLAG_BIN))
|
||||
USE_FTPGET(NEWTOY(ftpget, "<2>3P:cp:u:vgslLmMdD[-gs][!gslLmMdD][!clL]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_FTPPUT(OLDTOY(ftpput, ftpget, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_GETFATTR(NEWTOY(getfattr, "(only-values)dhn:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
|
||||
USE_GREP(NEWTOY(grep, "(line-buffered)(color):;(exclude-dir)*S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rRsvwcl(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EFw]", TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GUNZIP(NEWTOY(gunzip, "cdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_GZIP(NEWTOY(gzip, "ncdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_HEAD(NEWTOY(head, "?n(lines)#<0=10c(bytes)#<0qv[-nc]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_HELLO(NEWTOY(hello, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_HELP(NEWTOY(help, ""USE_HELP_EXTRAS("ah"), TOYFLAG_BIN))
|
||||
USE_HEXEDIT(NEWTOY(hexedit, "<1>1r", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_HOST(NEWTOY(host, "<1>2avt:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_HOSTID(NEWTOY(hostid, ">0", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_HOSTNAME(NEWTOY(hostname, ">1bdsfF:[!bdsf]", TOYFLAG_BIN))
|
||||
USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_SBIN))
|
||||
USE_I2CDETECT(NEWTOY(i2cdetect, ">3aFly", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_I2CDUMP(NEWTOY(i2cdump, "<2>2fy", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_I2CGET(NEWTOY(i2cget, "<3>3fy", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_I2CSET(NEWTOY(i2cset, "<4fy", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ICONV(NEWTOY(iconv, "cst:f:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ID(NEWTOY(id, ">1"USE_ID_Z("Z")"nGgru[!"USE_ID_Z("Z")"Ggu]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IFCONFIG(NEWTOY(ifconfig, "^?aS", TOYFLAG_SBIN))
|
||||
USE_INIT(NEWTOY(init, "", TOYFLAG_SBIN))
|
||||
USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
|
||||
USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
|
||||
USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
|
||||
USE_IPCRM(NEWTOY(ipcrm, "m*M*s*S*q*Q*", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IPCS(NEWTOY(ipcs, "acptulsqmi#", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_IP(OLDTOY(iplink, ip, TOYFLAG_SBIN))
|
||||
USE_IP(OLDTOY(iproute, ip, TOYFLAG_SBIN))
|
||||
USE_IP(OLDTOY(iprule, ip, TOYFLAG_SBIN))
|
||||
USE_IP(OLDTOY(iptunnel, ip, TOYFLAG_SBIN))
|
||||
USE_KILL(NEWTOY(kill, "?ls: ", TOYFLAG_BIN))
|
||||
USE_KILLALL(NEWTOY(killall, "?s:ilqvw", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_KILLALL5(NEWTOY(killall5, "?o*ls: [!lo][!ls]", TOYFLAG_SBIN))
|
||||
USE_KLOGD(NEWTOY(klogd, "c#<1>8n", TOYFLAG_SBIN))
|
||||
USE_LAST(NEWTOY(last, "f:W", TOYFLAG_BIN))
|
||||
USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LN(NEWTOY(ln, "<1t:Tvnfs", TOYFLAG_BIN))
|
||||
USE_LOAD_POLICY(NEWTOY(load_policy, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_LOG(NEWTOY(log, "<1p:t:", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_LOGGER(NEWTOY(logger, "st:p:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LOGIN(NEWTOY(login, ">1f:ph:", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
|
||||
USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LOGWRAPPER(NEWTOY(logwrapper, 0, TOYFLAG_NOHELP|TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LOSETUP(NEWTOY(losetup, ">2S(sizelimit)#s(show)ro#j:fdcaD[!afj]", TOYFLAG_SBIN))
|
||||
USE_LS(NEWTOY(ls, "(color):;(full-time)(show-control-chars)ZgoACFHLRSabcdfhikl@mnpqrstux1[-Cxm1][-Cxml][-Cxmo][-Cxmg][-cu][-ftS][-HL][!qb]", TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_LSATTR(NEWTOY(lsattr, "vldaR", TOYFLAG_BIN))
|
||||
USE_LSMOD(NEWTOY(lsmod, NULL, TOYFLAG_SBIN))
|
||||
USE_LSOF(NEWTOY(lsof, "lp*t", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LSPCI(NEWTOY(lspci, "emkn"USE_LSPCI_TEXT("@i:"), TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_LSUSB(NEWTOY(lsusb, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MAKEDEVS(NEWTOY(makedevs, "<1>1d:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MAN(NEWTOY(man, "k:M:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MCOOKIE(NEWTOY(mcookie, "v(verbose)V(version)", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MD5SUM(NEWTOY(md5sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MDEV(NEWTOY(mdev, "s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
|
||||
USE_MICROCOM(NEWTOY(microcom, "<1>1s:X", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MIX(NEWTOY(mix, "c:d:l#r#", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MKDIR(NEWTOY(mkdir, "<1"USE_MKDIR_Z("Z:")"vp(parent)(parents)m:", TOYFLAG_BIN|TOYFLAG_UMASK))
|
||||
USE_MKE2FS(NEWTOY(mke2fs, "<1>2g:Fnqm#N#i#b#", TOYFLAG_SBIN))
|
||||
USE_MKFIFO(NEWTOY(mkfifo, "<1"USE_MKFIFO_Z("Z:")"m:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MKNOD(NEWTOY(mknod, "<2>4m(mode):"USE_MKNOD_Z("Z:"), TOYFLAG_BIN|TOYFLAG_UMASK))
|
||||
USE_MKPASSWD(NEWTOY(mkpasswd, ">2S:m:P#=0<0", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MKSWAP(NEWTOY(mkswap, "<1>1L:", TOYFLAG_SBIN))
|
||||
USE_MKTEMP(NEWTOY(mktemp, ">1(tmpdir);:uqd(directory)p:t", TOYFLAG_BIN))
|
||||
USE_MODINFO(NEWTOY(modinfo, "<1b:k:F:0", TOYFLAG_SBIN))
|
||||
USE_MODPROBE(NEWTOY(modprobe, "alrqvsDbd*", TOYFLAG_SBIN))
|
||||
USE_MORE(NEWTOY(more, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_MOUNT(NEWTOY(mount, "?O:afnrvwt:o*[-rw]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
USE_MOUNTPOINT(NEWTOY(mountpoint, "<1qdx[-dx]", TOYFLAG_BIN))
|
||||
USE_MV(NEWTOY(mv, "<2vnF(remove-destination)fi[-ni]", TOYFLAG_BIN))
|
||||
USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", 0))
|
||||
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN))
|
||||
USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
|
||||
USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_BIN))
|
||||
USE_NL(NEWTOY(nl, "v#=1l#w#<0=6Eb:n:s:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NOHUP(NEWTOY(nohup, "<1^", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125)))
|
||||
USE_NPROC(NEWTOY(nproc, "(all)", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
|
||||
USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
|
||||
USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
|
||||
USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_PATCH(NEWTOY(patch, "(no-backup-if-mismatch)(dry-run)"USE_TOYBOX_DEBUG("x")"g#fulp#d:i:Rs(quiet)", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PIDOF(NEWTOY(pidof, "<1so:x", TOYFLAG_BIN))
|
||||
USE_PING(NEWTOY(ping, "<1>1m#t#<0>255=64c#<0=3s#<0>4088=56i%W#<0=3w#<0qf46I:[-46]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PING(OLDTOY(ping6, ping, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PIVOT_ROOT(NEWTOY(pivot_root, "<2>2", TOYFLAG_SBIN))
|
||||
USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PMAP(NEWTOY(pmap, "<1xq", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_PRINTENV(NEWTOY(printenv, "0(null)", TOYFLAG_BIN))
|
||||
USE_PRINTF(NEWTOY(printf, "<1?^", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ULIMIT(OLDTOY(prlimit, ulimit, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_PWD(NEWTOY(pwd, ">0LP[-LP]", TOYFLAG_BIN))
|
||||
USE_PWDX(NEWTOY(pwdx, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
|
||||
USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_RESTORECON(NEWTOY(restorecon, "<1DFnRrv", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_REV(NEWTOY(rev, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_RFKILL(NEWTOY(rfkill, "<1>2", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_RM(NEWTOY(rm, "fiRrv[-fi]", TOYFLAG_BIN))
|
||||
USE_RMDIR(NEWTOY(rmdir, "<1(ignore-fail-on-non-empty)p", TOYFLAG_BIN))
|
||||
USE_RMMOD(NEWTOY(rmmod, "<1wf", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_ROUTE(NEWTOY(route, "?neA:", TOYFLAG_BIN))
|
||||
USE_RUNCON(NEWTOY(runcon, "<2", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_SED(NEWTOY(sed, "(help)(version)e*f*i:;nErz(null-data)[+Er]", TOYFLAG_BIN|TOYFLAG_LOCALE|TOYFLAG_NOHELP))
|
||||
USE_SENDEVENT(NEWTOY(sendevent, "<4>4", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
|
||||
USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
|
||||
USE_SHA1SUM(NEWTOY(sha1sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TOYBOX_LIBCRYPTO(USE_SHA224SUM(OLDTOY(sha224sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
|
||||
USE_TOYBOX_LIBCRYPTO(USE_SHA256SUM(OLDTOY(sha256sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
|
||||
USE_TOYBOX_LIBCRYPTO(USE_SHA384SUM(OLDTOY(sha384sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
|
||||
USE_TOYBOX_LIBCRYPTO(USE_SHA512SUM(OLDTOY(sha512sum, sha1sum, TOYFLAG_USR|TOYFLAG_BIN)))
|
||||
USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SKELETON(NEWTOY(skeleton, "(walrus)(blubber):;(also):e@d*c#b:a", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SKELETON_ALIAS(NEWTOY(skeleton_alias, "b#dq", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN))
|
||||
USE_SNTP(NEWTOY(sntp, "M:m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
|
||||
USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1[!bl]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_STAT(NEWTOY(stat, "<1c:(format)fLt", TOYFLAG_BIN))
|
||||
USE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN))
|
||||
USE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
|
||||
USE_SULOGIN(NEWTOY(sulogin, "t#<0=0", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_SWAPOFF(NEWTOY(swapoff, "<1>1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_SWAPON(NEWTOY(swapon, "<1>1p#<0>32767d", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
|
||||
USE_SWITCH_ROOT(NEWTOY(switch_root, "<2c:h", TOYFLAG_SBIN))
|
||||
USE_SYNC(NEWTOY(sync, NULL, TOYFLAG_BIN))
|
||||
USE_SYSCTL(NEWTOY(sysctl, "^neNqwpaA[!ap][!aq][!aw][+aA]", TOYFLAG_SBIN))
|
||||
USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
|
||||
USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TAIL(NEWTOY(tail, "?fc-n-[-cn]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TAR(NEWTOY(tar, "&(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TELNET(NEWTOY(telnet, "<1>2", TOYFLAG_BIN))
|
||||
USE_TELNETD(NEWTOY(telnetd, "w#<0b:p#<0>65535=23f:l:FSKi[!wi]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TEST(NEWTOY(test, 0, TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NOHELP|TOYFLAG_MAYFORK))
|
||||
USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
|
||||
USE_TIME(NEWTOY(time, "<1^pv", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TIMEOUT(NEWTOY(timeout, "<2^(foreground)(preserve-status)vk:s(signal):", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(125)))
|
||||
USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d%<100=3000m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_TOUCH(NEWTOY(touch, "<1acd:fmr:t:h[!dtr]", TOYFLAG_BIN))
|
||||
USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
|
||||
USE_TR(NEWTOY(tr, "^>2<1Ccsd[+cC]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TRACEROUTE(NEWTOY(traceroute, "<1>2i:f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN|TOYFLAG_NOHELP))
|
||||
USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TUNCTL(NEWTOY(tunctl, "<1>1t|d|u:T[!td]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_TCPSVD(OLDTOY(udpsvd, tcpsvd, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ULIMIT(NEWTOY(ulimit, ">1P#<1SHavutsrRqpnmlifedc[-SH][!apvutsrRqnmlifedc]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
USE_UNAME(NEWTOY(uname, "oamvrns[+os]", TOYFLAG_BIN))
|
||||
USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_UNIX2DOS(NEWTOY(unix2dos, 0, TOYFLAG_BIN))
|
||||
USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_UNSHARE(NEWTOY(unshare, "<1^f(fork);r(map-root-user);i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_UPTIME(NEWTOY(uptime, ">0ps", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_UMASK|TOYFLAG_SBIN))
|
||||
USE_USERDEL(NEWTOY(userdel, "<1>1r", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_USLEEP(NEWTOY(usleep, "<1", TOYFLAG_BIN))
|
||||
USE_UUDECODE(NEWTOY(uudecode, ">1o:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_UMASK))
|
||||
USE_UUENCODE(NEWTOY(uuencode, "<1>2m", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_UUIDGEN(NEWTOY(uuidgen, ">0r(random)", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_VCONFIG(NEWTOY(vconfig, "<2>4", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_VI(NEWTOY(vi, "<1>1", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_VMSTAT(NEWTOY(vmstat, ">2n", TOYFLAG_BIN))
|
||||
USE_W(NEWTOY(w, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
|
||||
USE_WGET(NEWTOY(wget, "(no-check-certificate)O:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_XARGS(NEWTOY(xargs, "^E:P#optrn#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_XXD(NEWTOY(xxd, ">1c#l#o#g#<1=2iprs#[!rs]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_XZCAT(NEWTOY(xzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_YES(NEWTOY(yes, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_ZCAT(NEWTOY(zcat, "cdfk123456789[-123456789]", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
@@ -0,0 +1,140 @@
|
||||
#define DD_conv_fsync 0
|
||||
#define _DD_conv_fsync (1<<0)
|
||||
#define DD_conv_noerror 1
|
||||
#define _DD_conv_noerror (1<<1)
|
||||
#define DD_conv_notrunc 2
|
||||
#define _DD_conv_notrunc (1<<2)
|
||||
#define DD_conv_sync 3
|
||||
#define _DD_conv_sync (1<<3)
|
||||
#define DD_iflag_count_bytes 0
|
||||
#define _DD_iflag_count_bytes (1<<0)
|
||||
#define DD_iflag_skip_bytes 1
|
||||
#define _DD_iflag_skip_bytes (1<<1)
|
||||
#define DD_oflag_seek_bytes 0
|
||||
#define _DD_oflag_seek_bytes (1<<0)
|
||||
#define CP_mode 0
|
||||
#define _CP_mode (1<<0)
|
||||
#define CP_ownership 1
|
||||
#define _CP_ownership (1<<1)
|
||||
#define CP_timestamps 2
|
||||
#define _CP_timestamps (1<<2)
|
||||
#define CP_context 3
|
||||
#define _CP_context (1<<3)
|
||||
#define CP_xattr 4
|
||||
#define _CP_xattr (1<<4)
|
||||
#define PS_PID 0
|
||||
#define _PS_PID (1<<0)
|
||||
#define PS_PPID 1
|
||||
#define _PS_PPID (1<<1)
|
||||
#define PS_PRI 2
|
||||
#define _PS_PRI (1<<2)
|
||||
#define PS_NI 3
|
||||
#define _PS_NI (1<<3)
|
||||
#define PS_ADDR 4
|
||||
#define _PS_ADDR (1<<4)
|
||||
#define PS_SZ 5
|
||||
#define _PS_SZ (1<<5)
|
||||
#define PS_RSS 6
|
||||
#define _PS_RSS (1<<6)
|
||||
#define PS_PGID 7
|
||||
#define _PS_PGID (1<<7)
|
||||
#define PS_VSZ 8
|
||||
#define _PS_VSZ (1<<8)
|
||||
#define PS_MAJFL 9
|
||||
#define _PS_MAJFL (1<<9)
|
||||
#define PS_MINFL 10
|
||||
#define _PS_MINFL (1<<10)
|
||||
#define PS_PR 11
|
||||
#define _PS_PR (1<<11)
|
||||
#define PS_PSR 12
|
||||
#define _PS_PSR (1<<12)
|
||||
#define PS_RTPRIO 13
|
||||
#define _PS_RTPRIO (1<<13)
|
||||
#define PS_SCH 14
|
||||
#define _PS_SCH (1<<14)
|
||||
#define PS_CPU 15
|
||||
#define _PS_CPU (1<<15)
|
||||
#define PS_TID 16
|
||||
#define _PS_TID (1<<16)
|
||||
#define PS_TCNT 17
|
||||
#define _PS_TCNT (1<<17)
|
||||
#define PS_BIT 18
|
||||
#define _PS_BIT (1<<18)
|
||||
#define PS_TTY 19
|
||||
#define _PS_TTY (1<<19)
|
||||
#define PS_WCHAN 20
|
||||
#define _PS_WCHAN (1<<20)
|
||||
#define PS_LABEL 21
|
||||
#define _PS_LABEL (1<<21)
|
||||
#define PS_COMM 22
|
||||
#define _PS_COMM (1<<22)
|
||||
#define PS_NAME 23
|
||||
#define _PS_NAME (1<<23)
|
||||
#define PS_COMMAND 24
|
||||
#define _PS_COMMAND (1<<24)
|
||||
#define PS_CMDLINE 25
|
||||
#define _PS_CMDLINE (1<<25)
|
||||
#define PS_ARGS 26
|
||||
#define _PS_ARGS (1<<26)
|
||||
#define PS_CMD 27
|
||||
#define _PS_CMD (1<<27)
|
||||
#define PS_UID 28
|
||||
#define _PS_UID (1<<28)
|
||||
#define PS_USER 29
|
||||
#define _PS_USER (1<<29)
|
||||
#define PS_RUID 30
|
||||
#define _PS_RUID (1<<30)
|
||||
#define PS_RUSER 31
|
||||
#define _PS_RUSER (1<<31)
|
||||
#define PS_GID 32
|
||||
#define _PS_GID (1LL<<32)
|
||||
#define PS_GROUP 33
|
||||
#define _PS_GROUP (1LL<<33)
|
||||
#define PS_RGID 34
|
||||
#define _PS_RGID (1LL<<34)
|
||||
#define PS_RGROUP 35
|
||||
#define _PS_RGROUP (1LL<<35)
|
||||
#define PS_TIME 36
|
||||
#define _PS_TIME (1LL<<36)
|
||||
#define PS_ELAPSED 37
|
||||
#define _PS_ELAPSED (1LL<<37)
|
||||
#define PS_TIME_ 38
|
||||
#define _PS_TIME_ (1LL<<38)
|
||||
#define PS_C 39
|
||||
#define _PS_C (1LL<<39)
|
||||
#define PS__VSZ 40
|
||||
#define _PS__VSZ (1LL<<40)
|
||||
#define PS__MEM 41
|
||||
#define _PS__MEM (1LL<<41)
|
||||
#define PS__CPU 42
|
||||
#define _PS__CPU (1LL<<42)
|
||||
#define PS_VIRT 43
|
||||
#define _PS_VIRT (1LL<<43)
|
||||
#define PS_RES 44
|
||||
#define _PS_RES (1LL<<44)
|
||||
#define PS_SHR 45
|
||||
#define _PS_SHR (1LL<<45)
|
||||
#define PS_READ 46
|
||||
#define _PS_READ (1LL<<46)
|
||||
#define PS_WRITE 47
|
||||
#define _PS_WRITE (1LL<<47)
|
||||
#define PS_IO 48
|
||||
#define _PS_IO (1LL<<48)
|
||||
#define PS_DREAD 49
|
||||
#define _PS_DREAD (1LL<<49)
|
||||
#define PS_DWRITE 50
|
||||
#define _PS_DWRITE (1LL<<50)
|
||||
#define PS_SWAP 51
|
||||
#define _PS_SWAP (1LL<<51)
|
||||
#define PS_DIO 52
|
||||
#define _PS_DIO (1LL<<52)
|
||||
#define PS_STIME 53
|
||||
#define _PS_STIME (1LL<<53)
|
||||
#define PS_F 54
|
||||
#define _PS_F (1LL<<54)
|
||||
#define PS_S 55
|
||||
#define _PS_S (1LL<<55)
|
||||
#define PS_STAT 56
|
||||
#define _PS_STAT (1LL<<56)
|
||||
#define PS_PCY 57
|
||||
#define _PS_PCY (1LL<<57)
|
||||
@@ -0,0 +1,77 @@
|
||||
# ===========================================================================
|
||||
# Kernel configuration targets
|
||||
# These targets are used from top-level makefile
|
||||
|
||||
KCONFIG_TOP = Config.in
|
||||
KCONFIG_PROJECT = ToyBox
|
||||
obj = ./kconfig
|
||||
PHONY += clean help oldconfig menuconfig config silentoldconfig \
|
||||
randconfig allyesconfig allnoconfig allmodconfig defconfig
|
||||
|
||||
menuconfig: $(obj)/mconf $(KCONFIG_TOP)
|
||||
$< $(KCONFIG_TOP)
|
||||
|
||||
config: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< $(KCONFIG_TOP)
|
||||
|
||||
oldconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< -o $(KCONFIG_TOP)
|
||||
|
||||
silentoldconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
yes | $< -o $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
randconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< -r $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
allyesconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< -y $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
allnoconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< -n $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
defconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
$< -D /dev/null $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
macos_defconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
KCONFIG_ALLCONFIG=$(obj)/macos_miniconfig $< -n $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
bsd_defconfig: $(obj)/conf $(KCONFIG_TOP)
|
||||
KCONFIG_ALLCONFIG=$(obj)/freebsd_miniconfig $< -n $(KCONFIG_TOP) > /dev/null
|
||||
|
||||
# Help text used by make help
|
||||
help::
|
||||
@echo ' config - Update current config utilising a line-oriented program'
|
||||
@echo ' menuconfig - Update current config utilising a menu based program'
|
||||
@echo ' oldconfig - Update current config utilising a provided .config as base'
|
||||
@echo ' silentoldconfig - Same as oldconfig, but quietly'
|
||||
@echo ' randconfig - New config with random answer to all options'
|
||||
@echo ' defconfig - New config with default answer to all options'
|
||||
@echo ' This is the maximum sane configuration.'
|
||||
@echo ' allyesconfig - New config where all options are accepted with yes'
|
||||
@echo " This may not actually compile, it's a starting point"
|
||||
@echo ' for further configuration (probably with menuconfig)'
|
||||
@echo ' allnoconfig - New config where all options are answered with no'
|
||||
@echo ' (NOP binary, starting point for further configuration)'
|
||||
@echo ' macos_defconfig - Select commands known to build on macosx'
|
||||
@echo ' bsd_defconfig - Select commands known to build on freebsd'
|
||||
|
||||
# Cheesy build
|
||||
|
||||
SHIPPED = kconfig/zconf.tab.c kconfig/lex.zconf.c kconfig/zconf.hash.c
|
||||
|
||||
%.c: %.c_shipped
|
||||
@ln -s $(notdir $<) $@
|
||||
|
||||
gen_config.h: .config
|
||||
|
||||
kconfig/mconf: $(SHIPPED)
|
||||
$(HOSTCC) -o $@ kconfig/mconf.c kconfig/zconf.tab.c \
|
||||
kconfig/lxdialog/*.c -lcurses -DCURSES_LOC="<ncurses.h>" \
|
||||
-DKBUILD_NO_NLS=1 -DPROJECT_NAME=\"$(KCONFIG_PROJECT)\"
|
||||
|
||||
kconfig/conf: $(SHIPPED)
|
||||
$(HOSTCC) -o $@ kconfig/conf.c kconfig/zconf.tab.c -DKBUILD_NO_NLS=1 \
|
||||
-DPROJECT_NAME=\"$(KCONFIG_PROJECT)\"
|
||||
|
||||
clean::
|
||||
@rm -f $(wildcard kconfig/*zconf*.c) kconfig/conf kconfig/mconf
|
||||
@@ -0,0 +1,29 @@
|
||||
This is a snapshot of linux 2.6.12 kconfig as washed through busybox and
|
||||
further modified by Rob Landley.
|
||||
|
||||
Note: The build infrastructure in this directory is still GPLv2. Cleaning
|
||||
that out is a TODO item, but it doesn't affect the resulting binary.
|
||||
|
||||
Way back when I tried to push my local changes to kconfig upstream
|
||||
in 2005 https://lwn.net/Articles/161086/
|
||||
and 2006 http://lkml.iu.edu/hypermail/linux/kernel/0607.0/1805.html
|
||||
and 2007 http://lkml.iu.edu/hypermail/linux/kernel/0707.1/1741.html
|
||||
each of which spawned long "I think you should go do this and this and this
|
||||
but I'm not going to lift a finger personally" threads from the kernel
|
||||
developers. Twice I came back a year later to see if there was any interest
|
||||
in what I _had_ done, and the third thread was the longest of the lot but
|
||||
no code was merged as a result.
|
||||
|
||||
*shrug* That's the linux-kernel community for you. I had an easier time
|
||||
than the author of squashfs, who spent 5 years actively trying to get his code
|
||||
merged, finally quitting his job to spend an unpaid year working on upstreaming
|
||||
squashfs _after_ after every major Linux distro had been locally carrying it
|
||||
for years. No really, here's where he wrote about it himself:
|
||||
|
||||
https://lwn.net/Articles/563578/
|
||||
|
||||
This code is _going_away_. Rewriting it is low priority, but removing it is a
|
||||
checklist item for the 1.0 toybox release. This directory contains the only
|
||||
GPL code left in the tree, and none of its code winds up in the resulting
|
||||
binary. It's just an editor that reads our Config.in files to update the top
|
||||
level .config file; you can edit they by hand if you really want to.
|
||||
+624
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define LKC_DIRECT_LINK
|
||||
#include "lkc.h"
|
||||
|
||||
static void conf(struct menu *menu);
|
||||
static void check_conf(struct menu *menu);
|
||||
|
||||
enum {
|
||||
ask_all,
|
||||
ask_new,
|
||||
ask_silent,
|
||||
set_default,
|
||||
set_yes,
|
||||
set_mod,
|
||||
set_no,
|
||||
set_random
|
||||
} input_mode = ask_all;
|
||||
char *defconfig_file;
|
||||
|
||||
static int indent = 1;
|
||||
static int valid_stdin = 1;
|
||||
static int conf_cnt;
|
||||
static char line[128];
|
||||
static struct menu *rootEntry;
|
||||
|
||||
static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
|
||||
|
||||
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 && input_mode == ask_silent) {
|
||||
printf(_("aborted!\n\n"));
|
||||
printf(_("Console input/output is redirected. "));
|
||||
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_askvalue(struct symbol *sym, const char *def)
|
||||
{
|
||||
enum symbol_type type = sym_get_type(sym);
|
||||
tristate val;
|
||||
|
||||
if (!sym_has_value(sym))
|
||||
printf("(NEW) ");
|
||||
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
|
||||
if (!sym_is_changable(sym)) {
|
||||
printf("%s\n", def);
|
||||
line[0] = '\n';
|
||||
line[1] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (input_mode) {
|
||||
case set_no:
|
||||
case set_mod:
|
||||
case set_yes:
|
||||
case set_random:
|
||||
if (sym_has_value(sym)) {
|
||||
printf("%s\n", def);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ask_new:
|
||||
case ask_silent:
|
||||
if (sym_has_value(sym)) {
|
||||
printf("%s\n", def);
|
||||
return;
|
||||
}
|
||||
check_stdin();
|
||||
case ask_all:
|
||||
fflush(stdout);
|
||||
fgets(line, 128, stdin);
|
||||
return;
|
||||
case set_default:
|
||||
printf("%s\n", def);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
case S_STRING:
|
||||
printf("%s\n", def);
|
||||
return;
|
||||
default:
|
||||
;
|
||||
}
|
||||
switch (input_mode) {
|
||||
case set_yes:
|
||||
if (sym_tristate_within_range(sym, yes)) {
|
||||
line[0] = 'y';
|
||||
line[1] = '\n';
|
||||
line[2] = 0;
|
||||
break;
|
||||
}
|
||||
case set_mod:
|
||||
if (type == S_TRISTATE) {
|
||||
if (sym_tristate_within_range(sym, mod)) {
|
||||
line[0] = 'm';
|
||||
line[1] = '\n';
|
||||
line[2] = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (sym_tristate_within_range(sym, yes)) {
|
||||
line[0] = 'y';
|
||||
line[1] = '\n';
|
||||
line[2] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case set_no:
|
||||
if (sym_tristate_within_range(sym, no)) {
|
||||
line[0] = 'n';
|
||||
line[1] = '\n';
|
||||
line[2] = 0;
|
||||
break;
|
||||
}
|
||||
case set_random:
|
||||
do {
|
||||
val = (tristate)(random() % 3);
|
||||
} while (!sym_tristate_within_range(sym, val));
|
||||
switch (val) {
|
||||
case no: line[0] = 'n'; break;
|
||||
case mod: line[0] = 'm'; break;
|
||||
case yes: line[0] = 'y'; break;
|
||||
}
|
||||
line[1] = '\n';
|
||||
line[2] = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("%s", line);
|
||||
}
|
||||
|
||||
int conf_string(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym = menu->sym;
|
||||
const char *def, *help;
|
||||
|
||||
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);
|
||||
conf_askvalue(sym, def);
|
||||
switch (line[0]) {
|
||||
case '\n':
|
||||
break;
|
||||
case '?':
|
||||
/* print help */
|
||||
if (line[1] == '\n') {
|
||||
help = nohelp_text;
|
||||
if (menu->sym->help)
|
||||
help = menu->sym->help;
|
||||
printf("\n%s\n", menu->sym->help);
|
||||
def = NULL;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
int type;
|
||||
tristate oldval, newval;
|
||||
const char *help;
|
||||
|
||||
while (1) {
|
||||
printf("%*s%s ", indent - 1, "", menu->prompt->text);
|
||||
if (sym->name)
|
||||
printf("(%s) ", sym->name);
|
||||
type = sym_get_type(sym);
|
||||
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 (sym->help)
|
||||
printf("/?");
|
||||
printf("] ");
|
||||
conf_askvalue(sym, sym_get_string_value(sym));
|
||||
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:
|
||||
help = nohelp_text;
|
||||
if (sym->help)
|
||||
help = sym->help;
|
||||
printf("\n%s\n", help);
|
||||
}
|
||||
}
|
||||
|
||||
static int conf_choice(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym, *def_sym;
|
||||
struct menu *child;
|
||||
int type;
|
||||
bool is_new;
|
||||
|
||||
sym = menu->sym;
|
||||
type = sym_get_type(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(" (NEW)");
|
||||
printf("\n");
|
||||
}
|
||||
printf("%*schoice", indent - 1, "");
|
||||
if (cnt == 1) {
|
||||
printf("[1]: 1\n");
|
||||
goto conf_childs;
|
||||
}
|
||||
printf("[1-%d", cnt);
|
||||
if (sym->help)
|
||||
printf("?");
|
||||
printf("]: ");
|
||||
switch (input_mode) {
|
||||
case ask_new:
|
||||
case ask_silent:
|
||||
if (!is_new) {
|
||||
cnt = def;
|
||||
printf("%d\n", cnt);
|
||||
break;
|
||||
}
|
||||
check_stdin();
|
||||
case ask_all:
|
||||
fflush(stdout);
|
||||
fgets(line, 128, stdin);
|
||||
strip(line);
|
||||
if (line[0] == '?') {
|
||||
printf("\n%s\n", menu->sym->help ?
|
||||
menu->sym->help : nohelp_text);
|
||||
continue;
|
||||
}
|
||||
if (!line[0])
|
||||
cnt = def;
|
||||
else if (isdigit(line[0]))
|
||||
cnt = atoi(line);
|
||||
else
|
||||
continue;
|
||||
break;
|
||||
case set_random:
|
||||
def = (random() % cnt) + 1;
|
||||
case set_default:
|
||||
case set_yes:
|
||||
case set_mod:
|
||||
case set_no:
|
||||
cnt = def;
|
||||
printf("%d\n", cnt);
|
||||
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[strlen(line) - 1] == '?') {
|
||||
printf("\n%s\n", child->sym->help ?
|
||||
child->sym->help : nohelp_text);
|
||||
continue;
|
||||
}
|
||||
sym_set_choice_value(sym, child->sym);
|
||||
if (child->list) {
|
||||
indent += 2;
|
||||
conf(child->list);
|
||||
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 == ask_silent && rootEntry != menu) {
|
||||
check_conf(menu);
|
||||
return;
|
||||
}
|
||||
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 (!conf_cnt++)
|
||||
printf(_("*\n* Restart config...\n*\n"));
|
||||
rootEntry = menu_get_parent_menu(menu);
|
||||
conf(rootEntry);
|
||||
}
|
||||
}
|
||||
|
||||
for (child = menu->list; child; child = child->next)
|
||||
check_conf(child);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int i = 1;
|
||||
const char *name;
|
||||
struct stat tmpstat;
|
||||
|
||||
if (ac > i && av[i][0] == '-') {
|
||||
switch (av[i++][1]) {
|
||||
case 'o':
|
||||
input_mode = ask_new;
|
||||
break;
|
||||
case 's':
|
||||
input_mode = ask_silent;
|
||||
valid_stdin = isatty(0) && isatty(1) && isatty(2);
|
||||
break;
|
||||
case 'd':
|
||||
input_mode = set_default;
|
||||
break;
|
||||
case 'D':
|
||||
input_mode = set_default;
|
||||
defconfig_file = av[i++];
|
||||
if (!defconfig_file) {
|
||||
printf(_("%s: No default config file specified\n"),
|
||||
av[0]);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
input_mode = set_no;
|
||||
break;
|
||||
case 'm':
|
||||
input_mode = set_mod;
|
||||
break;
|
||||
case 'y':
|
||||
input_mode = set_yes;
|
||||
break;
|
||||
case 'r':
|
||||
input_mode = set_random;
|
||||
srandom(time(NULL));
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
fprintf(stderr, "See README for usage info\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
name = av[i];
|
||||
if (!name) {
|
||||
printf(_("%s: Kconfig file missing\n"), av[0]);
|
||||
exit(1);
|
||||
}
|
||||
conf_parse(name);
|
||||
//zconfdump(stdout);
|
||||
switch (input_mode) {
|
||||
case set_default:
|
||||
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 ask_silent:
|
||||
if (stat(".config", &tmpstat)) {
|
||||
printf(_("***\n"
|
||||
"*** You have not yet configured your "PROJECT_NAME"!\n"
|
||||
"***\n"
|
||||
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
|
||||
"*** \"make menuconfig\" or \"make xconfig\").\n"
|
||||
"***\n"));
|
||||
exit(1);
|
||||
}
|
||||
case ask_all:
|
||||
case ask_new:
|
||||
conf_read(NULL);
|
||||
break;
|
||||
case set_no:
|
||||
case set_mod:
|
||||
case set_yes:
|
||||
case set_random:
|
||||
name = getenv("KCONFIG_ALLCONFIG");
|
||||
if (name && !stat(name, &tmpstat)) {
|
||||
conf_read_simple(name, S_DEF_USER);
|
||||
break;
|
||||
}
|
||||
switch (input_mode) {
|
||||
case set_no: name = "allno.config"; break;
|
||||
case set_mod: name = "allmod.config"; break;
|
||||
case set_yes: name = "allyes.config"; break;
|
||||
case set_random: name = "allrandom.config"; break;
|
||||
default: break;
|
||||
}
|
||||
if (!stat(name, &tmpstat))
|
||||
conf_read_simple(name, S_DEF_USER);
|
||||
else if (!stat("all.config", &tmpstat))
|
||||
conf_read_simple("all.config", S_DEF_USER);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (input_mode != ask_silent) {
|
||||
rootEntry = &rootmenu;
|
||||
conf(&rootmenu);
|
||||
if (input_mode == ask_all) {
|
||||
input_mode = ask_silent;
|
||||
valid_stdin = 1;
|
||||
}
|
||||
} else if (sym_change_count) {
|
||||
name = getenv("KCONFIG_NOSILENTUPDATE");
|
||||
if (name && *name) {
|
||||
fprintf(stderr, _("\n*** "PROJECT_NAME" configuration requires explicit update.\n\n"));
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
goto skip_check;
|
||||
|
||||
do {
|
||||
conf_cnt = 0;
|
||||
check_conf(&rootmenu);
|
||||
} while (conf_cnt);
|
||||
|
||||
if (!conf_write(NULL)) {
|
||||
skip_check:
|
||||
if (!(input_mode == ask_silent && conf_write_autoconf()))
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, _("\n*** Error writing "PROJECT_NAME" configuration.\n\n"));
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,806 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LKC_DIRECT_LINK
|
||||
#include "lkc.h"
|
||||
|
||||
static void conf_warning(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
static const char *conf_filename;
|
||||
static int conf_lineno, conf_warnings, conf_unsaved;
|
||||
|
||||
#ifndef conf_defname
|
||||
const char conf_defname[] = "arch/$ARCH/defconfig";
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_PREFIX
|
||||
#define CONFIG_PREFIX "CONFIG_"
|
||||
#endif
|
||||
|
||||
static void conf_warning(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
conf_warnings++;
|
||||
}
|
||||
|
||||
const char *conf_get_configname(void)
|
||||
{
|
||||
char *name = getenv("KCONFIG_CONFIG");
|
||||
|
||||
return name ? name : ".config";
|
||||
}
|
||||
|
||||
static char *conf_expand_value(const char *in)
|
||||
{
|
||||
struct symbol *sym;
|
||||
const char *src;
|
||||
static char res_value[SYMBOL_MAXLENGTH];
|
||||
char *dst, name[SYMBOL_MAXLENGTH];
|
||||
|
||||
res_value[0] = 0;
|
||||
dst = name;
|
||||
while ((src = strchr(in, '$'))) {
|
||||
strncat(res_value, in, src - in);
|
||||
src++;
|
||||
dst = name;
|
||||
while (isalnum(*src) || *src == '_')
|
||||
*dst++ = *src++;
|
||||
*dst = 0;
|
||||
sym = sym_lookup(name, 0);
|
||||
sym_calc_value(sym);
|
||||
strcat(res_value, sym_get_string_value(sym));
|
||||
in = src;
|
||||
}
|
||||
strcat(res_value, in);
|
||||
|
||||
return res_value;
|
||||
}
|
||||
|
||||
char *conf_get_default_confname(void)
|
||||
{
|
||||
struct stat buf;
|
||||
static char fullname[PATH_MAX+1];
|
||||
char *env, *name;
|
||||
|
||||
name = conf_expand_value(conf_defname);
|
||||
env = getenv(SRCTREE);
|
||||
if (env) {
|
||||
sprintf(fullname, "%s/%s", env, name);
|
||||
if (!stat(fullname, &buf))
|
||||
return fullname;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int conf_read_simple(const char *name, int def)
|
||||
{
|
||||
FILE *in = NULL;
|
||||
char line[1024];
|
||||
char *p, *p2;
|
||||
struct symbol *sym;
|
||||
int i, def_flags;
|
||||
|
||||
if (name) {
|
||||
in = zconf_fopen(name);
|
||||
} else {
|
||||
struct property *prop;
|
||||
|
||||
name = conf_get_configname();
|
||||
in = zconf_fopen(name);
|
||||
if (in)
|
||||
goto load;
|
||||
sym_change_count++;
|
||||
if (!sym_defconfig_list)
|
||||
return 1;
|
||||
|
||||
for_all_defaults(sym_defconfig_list, prop) {
|
||||
if (expr_calc_value(prop->visible.expr) == no ||
|
||||
prop->expr->type != E_SYMBOL)
|
||||
continue;
|
||||
name = conf_expand_value(prop->expr->left.sym->name);
|
||||
in = zconf_fopen(name);
|
||||
if (in) {
|
||||
printf(_("#\n"
|
||||
"# using defaults found in %s\n"
|
||||
"#\n"), name);
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!in)
|
||||
return 1;
|
||||
|
||||
load:
|
||||
conf_filename = name;
|
||||
conf_lineno = 0;
|
||||
conf_warnings = 0;
|
||||
conf_unsaved = 0;
|
||||
|
||||
def_flags = SYMBOL_DEF << def;
|
||||
for_all_symbols(i, sym) {
|
||||
sym->flags |= SYMBOL_CHANGED;
|
||||
sym->flags &= ~(def_flags|SYMBOL_VALID);
|
||||
if (sym_is_choice(sym))
|
||||
sym->flags |= def_flags;
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
case S_STRING:
|
||||
if (sym->def[def].val)
|
||||
free(sym->def[def].val);
|
||||
default:
|
||||
sym->def[def].val = NULL;
|
||||
sym->def[def].tri = no;
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), in)) {
|
||||
conf_lineno++;
|
||||
sym = NULL;
|
||||
switch (line[0]) {
|
||||
case '#':
|
||||
if (line[1]!=' ' || memcmp(line + 2, CONFIG_PREFIX,
|
||||
strlen(CONFIG_PREFIX))) {
|
||||
continue;
|
||||
}
|
||||
p = strchr(line + 2 + strlen(CONFIG_PREFIX), ' ');
|
||||
if (!p)
|
||||
continue;
|
||||
*p++ = 0;
|
||||
if (strncmp(p, "is not set", 10))
|
||||
continue;
|
||||
if (def == S_DEF_USER) {
|
||||
sym = sym_find(line + 2 + strlen(CONFIG_PREFIX));
|
||||
if (!sym) {
|
||||
conf_warning("trying to assign nonexistent symbol %s", line + 2 + strlen(CONFIG_PREFIX));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sym = sym_lookup(line + 9, 0);
|
||||
if (sym->type == S_UNKNOWN)
|
||||
sym->type = S_BOOLEAN;
|
||||
}
|
||||
if (sym->flags & def_flags) {
|
||||
conf_warning("trying to reassign symbol %s", sym->name);
|
||||
break;
|
||||
}
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
sym->def[def].tri = no;
|
||||
sym->flags |= def_flags;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 'A' ... 'Z':
|
||||
if (memcmp(line, CONFIG_PREFIX, strlen(CONFIG_PREFIX))) {
|
||||
conf_warning("unexpected data");
|
||||
continue;
|
||||
}
|
||||
p = strchr(line + strlen(CONFIG_PREFIX), '=');
|
||||
if (!p)
|
||||
continue;
|
||||
*p++ = 0;
|
||||
p2 = strchr(p, '\n');
|
||||
if (p2) {
|
||||
*p2-- = 0;
|
||||
if (*p2 == '\r')
|
||||
*p2 = 0;
|
||||
}
|
||||
if (def == S_DEF_USER) {
|
||||
sym = sym_find(line + strlen(CONFIG_PREFIX));
|
||||
if (!sym) {
|
||||
conf_warning("trying to assign nonexistent symbol %s", line + 7);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sym = sym_lookup(line + strlen(CONFIG_PREFIX), 0);
|
||||
if (sym->type == S_UNKNOWN)
|
||||
sym->type = S_OTHER;
|
||||
}
|
||||
if (sym->flags & def_flags) {
|
||||
conf_warning("trying to reassign symbol %s", sym->name);
|
||||
break;
|
||||
}
|
||||
switch (sym->type) {
|
||||
case S_TRISTATE:
|
||||
if (p[0] == 'm') {
|
||||
sym->def[def].tri = mod;
|
||||
sym->flags |= def_flags;
|
||||
break;
|
||||
}
|
||||
case S_BOOLEAN:
|
||||
if (p[0] == 'y') {
|
||||
sym->def[def].tri = yes;
|
||||
sym->flags |= def_flags;
|
||||
break;
|
||||
}
|
||||
if (p[0] == 'n') {
|
||||
sym->def[def].tri = no;
|
||||
sym->flags |= def_flags;
|
||||
break;
|
||||
}
|
||||
conf_warning("symbol value '%s' invalid for %s", p, sym->name);
|
||||
break;
|
||||
case S_OTHER:
|
||||
if (*p != '"') {
|
||||
for (p2 = p; *p2 && !isspace(*p2); p2++)
|
||||
;
|
||||
sym->type = S_STRING;
|
||||
goto done;
|
||||
}
|
||||
case S_STRING:
|
||||
if (*p++ != '"')
|
||||
break;
|
||||
for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
|
||||
if (*p2 == '"') {
|
||||
*p2 = 0;
|
||||
break;
|
||||
}
|
||||
memmove(p2, p2 + 1, strlen(p2));
|
||||
}
|
||||
if (!p2) {
|
||||
conf_warning("invalid string found");
|
||||
continue;
|
||||
}
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
done:
|
||||
if (sym_string_valid(sym, p)) {
|
||||
sym->def[def].val = strdup(p);
|
||||
sym->flags |= def_flags;
|
||||
} else {
|
||||
conf_warning("symbol value '%s' invalid for %s", p, sym->name);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
break;
|
||||
default:
|
||||
conf_warning("unexpected data");
|
||||
continue;
|
||||
}
|
||||
if (sym && sym_is_choice_value(sym)) {
|
||||
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
|
||||
switch (sym->def[def].tri) {
|
||||
case no:
|
||||
break;
|
||||
case mod:
|
||||
if (cs->def[def].tri == yes) {
|
||||
conf_warning("%s creates inconsistent choice state", sym->name);
|
||||
cs->flags &= ~def_flags;
|
||||
}
|
||||
break;
|
||||
case yes:
|
||||
if (cs->def[def].tri != no) {
|
||||
conf_warning("%s creates inconsistent choice state", sym->name);
|
||||
cs->flags &= ~def_flags;
|
||||
} else
|
||||
cs->def[def].val = sym;
|
||||
break;
|
||||
}
|
||||
cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri);
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
|
||||
if (modules_sym)
|
||||
sym_calc_value(modules_sym);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_read(const char *name)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct expr *e;
|
||||
int i, flags;
|
||||
|
||||
sym_change_count = 0;
|
||||
|
||||
if (conf_read_simple(name, S_DEF_USER))
|
||||
return 1;
|
||||
|
||||
for_all_symbols(i, sym) {
|
||||
sym_calc_value(sym);
|
||||
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
|
||||
goto sym_ok;
|
||||
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
|
||||
/* check that calculated value agrees with saved value */
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
|
||||
break;
|
||||
if (!sym_is_choice(sym))
|
||||
goto sym_ok;
|
||||
default:
|
||||
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
|
||||
goto sym_ok;
|
||||
break;
|
||||
}
|
||||
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
|
||||
/* no previous value and not saved */
|
||||
goto sym_ok;
|
||||
conf_unsaved++;
|
||||
/* maybe print value in verbose mode... */
|
||||
sym_ok:
|
||||
if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
|
||||
if (sym->visible == no)
|
||||
sym->flags &= ~SYMBOL_DEF_USER;
|
||||
switch (sym->type) {
|
||||
case S_STRING:
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
|
||||
sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sym_is_choice(sym))
|
||||
continue;
|
||||
prop = sym_get_choice_prop(sym);
|
||||
flags = sym->flags;
|
||||
for (e = prop->expr; e; e = e->left.expr)
|
||||
if (e->right.sym->visible != no)
|
||||
flags &= e->right.sym->flags;
|
||||
sym->flags &= flags | ~SYMBOL_DEF_USER;
|
||||
}
|
||||
|
||||
sym_change_count += conf_warnings || conf_unsaved;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct menu *next_menu(struct menu *menu)
|
||||
{
|
||||
if (menu->list) return menu->list;
|
||||
do {
|
||||
if (menu->next) {
|
||||
menu = menu->next;
|
||||
break;
|
||||
}
|
||||
} while ((menu = menu->parent));
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
#define SYMBOL_FORCEWRITE (1<<31)
|
||||
|
||||
int conf_write(const char *name)
|
||||
{
|
||||
FILE *out;
|
||||
struct symbol *sym;
|
||||
struct menu *menu;
|
||||
const char *basename;
|
||||
char dirname[128], tmpname[128], newname[128];
|
||||
int type, l, writetype;
|
||||
const char *str;
|
||||
time_t now;
|
||||
int use_timestamp = 1;
|
||||
char *env;
|
||||
|
||||
dirname[0] = 0;
|
||||
if (name && name[0]) {
|
||||
struct stat st;
|
||||
char *slash;
|
||||
|
||||
if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
|
||||
strcpy(dirname, name);
|
||||
strcat(dirname, "/");
|
||||
basename = conf_get_configname();
|
||||
} else if ((slash = strrchr(name, '/'))) {
|
||||
int size = slash - name + 1;
|
||||
memcpy(dirname, name, size);
|
||||
dirname[size] = 0;
|
||||
if (slash[1])
|
||||
basename = slash + 1;
|
||||
else
|
||||
basename = conf_get_configname();
|
||||
} else
|
||||
basename = name;
|
||||
} else
|
||||
basename = conf_get_configname();
|
||||
|
||||
sprintf(newname, "%s%s", dirname, basename);
|
||||
env = getenv("KCONFIG_OVERWRITECONFIG");
|
||||
if (!env || !*env) {
|
||||
sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
|
||||
out = fopen(tmpname, "w");
|
||||
} else {
|
||||
*tmpname = 0;
|
||||
out = fopen(newname, "w");
|
||||
}
|
||||
if (!out)
|
||||
return 1;
|
||||
|
||||
sym = sym_lookup("KCONFIG_VERSION", 0);
|
||||
sym_calc_value(sym);
|
||||
time(&now);
|
||||
env = getenv("KCONFIG_NOTIMESTAMP");
|
||||
if (env && *env)
|
||||
use_timestamp = 0;
|
||||
|
||||
fprintf(out, _("#\n"
|
||||
"# Automatically generated make config: don't edit\n"
|
||||
"# "PROJECT_NAME" version: %s\n"
|
||||
"%s%s"
|
||||
"#\n"),
|
||||
sym_get_string_value(sym),
|
||||
use_timestamp ? "# " : "",
|
||||
use_timestamp ? ctime(&now) : "");
|
||||
|
||||
if (!sym_change_count)
|
||||
sym_clear_all_valid();
|
||||
|
||||
// Write out all symbols (even in closed sub-menus).
|
||||
if (1) {
|
||||
for (menu = rootmenu.list; menu; menu = next_menu(menu))
|
||||
if (menu->sym) menu->sym->flags |= SYMBOL_FORCEWRITE;
|
||||
writetype = SYMBOL_FORCEWRITE;
|
||||
|
||||
// Don't write out symbols in closed menus.
|
||||
|
||||
} else writetype = SYMBOL_WRITE;
|
||||
|
||||
|
||||
menu = rootmenu.list;
|
||||
while (menu) {
|
||||
sym = menu->sym;
|
||||
if (!sym) {
|
||||
if (!menu_is_visible(menu))
|
||||
goto next;
|
||||
str = menu_get_prompt(menu);
|
||||
fprintf(out, "\n"
|
||||
"#\n"
|
||||
"# %s\n"
|
||||
"#\n", str);
|
||||
} else if (!(sym->flags & SYMBOL_CHOICE)) {
|
||||
sym_calc_value(sym);
|
||||
if (!(sym->flags & writetype))
|
||||
goto next;
|
||||
sym->flags &= ~writetype;
|
||||
type = sym->type;
|
||||
if (type == S_TRISTATE) {
|
||||
sym_calc_value(modules_sym);
|
||||
if (modules_sym->curr.tri == no)
|
||||
type = S_BOOLEAN;
|
||||
}
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (sym_get_tristate_value(sym)) {
|
||||
case no:
|
||||
fprintf(out, "# "CONFIG_PREFIX"%s is not set\n", sym->name);
|
||||
break;
|
||||
case mod:
|
||||
fprintf(out, CONFIG_PREFIX"%s=m\n", sym->name);
|
||||
break;
|
||||
case yes:
|
||||
fprintf(out, CONFIG_PREFIX"%s=y\n", sym->name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case S_STRING:
|
||||
str = sym_get_string_value(sym);
|
||||
fprintf(out, CONFIG_PREFIX"%s=\"", sym->name);
|
||||
while (1) {
|
||||
l = strcspn(str, "\"\\");
|
||||
if (l) {
|
||||
fwrite(str, l, 1, out);
|
||||
str += l;
|
||||
}
|
||||
if (!*str)
|
||||
break;
|
||||
fprintf(out, "\\%c", *str++);
|
||||
}
|
||||
fputs("\"\n", out);
|
||||
break;
|
||||
case S_HEX:
|
||||
str = sym_get_string_value(sym);
|
||||
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
|
||||
fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, *str ? str : "0");
|
||||
break;
|
||||
}
|
||||
case S_INT:
|
||||
str = sym_get_string_value(sym);
|
||||
fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, *str ? str : "0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
next:
|
||||
if (writetype == SYMBOL_WRITE) {
|
||||
if (menu->list) {
|
||||
menu = menu->list;
|
||||
continue;
|
||||
}
|
||||
if (menu->next)
|
||||
menu = menu->next;
|
||||
else while ((menu = menu->parent)) {
|
||||
if (menu->next) {
|
||||
menu = menu->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
menu = next_menu(menu);
|
||||
}
|
||||
fclose(out);
|
||||
|
||||
if (*tmpname) {
|
||||
strcat(dirname, basename);
|
||||
strcat(dirname, ".old");
|
||||
rename(newname, dirname);
|
||||
if (rename(tmpname, newname))
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf(_("#\n"
|
||||
"# configuration written to %s\n"
|
||||
"#\n"), newname);
|
||||
|
||||
sym_change_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_split_config(void)
|
||||
{
|
||||
char *name, path[128];
|
||||
char *s, *d, c;
|
||||
struct symbol *sym;
|
||||
struct stat sb;
|
||||
int res, i, fd;
|
||||
|
||||
name = getenv("KCONFIG_AUTOCONFIG");
|
||||
if (!name)
|
||||
name = "include/config/auto.conf";
|
||||
conf_read_simple(name, S_DEF_AUTO);
|
||||
|
||||
if (chdir("include/config"))
|
||||
return 1;
|
||||
|
||||
res = 0;
|
||||
for_all_symbols(i, sym) {
|
||||
sym_calc_value(sym);
|
||||
if ((sym->flags & SYMBOL_AUTO) || !sym->name)
|
||||
continue;
|
||||
if (sym->flags & SYMBOL_WRITE) {
|
||||
if (sym->flags & SYMBOL_DEF_AUTO) {
|
||||
/*
|
||||
* symbol has old and new value,
|
||||
* so compare them...
|
||||
*/
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
if (sym_get_tristate_value(sym) ==
|
||||
sym->def[S_DEF_AUTO].tri)
|
||||
continue;
|
||||
break;
|
||||
case S_STRING:
|
||||
case S_HEX:
|
||||
case S_INT:
|
||||
if (!strcmp(sym_get_string_value(sym),
|
||||
sym->def[S_DEF_AUTO].val))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If there is no old value, only 'no' (unset)
|
||||
* is allowed as new value.
|
||||
*/
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
if (sym_get_tristate_value(sym) == no)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!(sym->flags & SYMBOL_DEF_AUTO))
|
||||
/* There is neither an old nor a new value. */
|
||||
continue;
|
||||
/* else
|
||||
* There is an old value, but no new value ('no' (unset)
|
||||
* isn't saved in auto.conf, so the old value is always
|
||||
* different from 'no').
|
||||
*/
|
||||
|
||||
/* Replace all '_' and append ".h" */
|
||||
s = sym->name;
|
||||
d = path;
|
||||
while ((c = *s++)) {
|
||||
c = tolower(c);
|
||||
*d++ = (c == '_') ? '/' : c;
|
||||
}
|
||||
strcpy(d, ".h");
|
||||
|
||||
/* Assume directory path already exists. */
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Create directory components,
|
||||
* unless they exist already.
|
||||
*/
|
||||
d = path;
|
||||
while ((d = strchr(d, '/'))) {
|
||||
*d = 0;
|
||||
if (stat(path, &sb) && mkdir(path, 0755)) {
|
||||
res = 1;
|
||||
goto out;
|
||||
}
|
||||
*d++ = '/';
|
||||
}
|
||||
/* Try it again. */
|
||||
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
out:
|
||||
if (chdir("../.."))
|
||||
return 1;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int conf_write_autoconf(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
const char *str;
|
||||
char *name;
|
||||
FILE *out, *out_h;
|
||||
time_t now;
|
||||
int i, l;
|
||||
|
||||
sym_clear_all_valid();
|
||||
|
||||
file_write_dep("include/config/auto.conf.cmd");
|
||||
|
||||
if (conf_split_config())
|
||||
return 1;
|
||||
|
||||
out = fopen(".tmpconfig", "w");
|
||||
if (!out)
|
||||
return 1;
|
||||
|
||||
out_h = fopen(".tmpconfig.h", "w");
|
||||
if (!out_h) {
|
||||
fclose(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sym = sym_lookup("KCONFIG_VERSION", 0);
|
||||
sym_calc_value(sym);
|
||||
time(&now);
|
||||
fprintf(out, "#\n"
|
||||
"# Automatically generated make config: don't edit\n"
|
||||
"# "PROJECT_NAME" version: %s\n"
|
||||
"# %s"
|
||||
"#\n",
|
||||
sym_get_string_value(sym), ctime(&now));
|
||||
fprintf(out_h, "/*\n"
|
||||
" * Automatically generated C config: don't edit\n"
|
||||
" * "PROJECT_NAME" version: %s\n"
|
||||
" * %s"
|
||||
" */\n"
|
||||
// "#define AUTOCONF_INCLUDED\n"
|
||||
, sym_get_string_value(sym), ctime(&now));
|
||||
|
||||
for_all_symbols(i, sym) {
|
||||
sym_calc_value(sym);
|
||||
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
|
||||
continue;
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (sym_get_tristate_value(sym)) {
|
||||
case no:
|
||||
break;
|
||||
case mod:
|
||||
fprintf(out, CONFIG_PREFIX"%s=m\n", sym->name);
|
||||
fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
|
||||
break;
|
||||
case yes:
|
||||
fprintf(out, CONFIG_PREFIX"%s=y\n", sym->name);
|
||||
fprintf(out_h, "#define "CONFIG_PREFIX"%s 1\n", sym->name);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case S_STRING:
|
||||
str = sym_get_string_value(sym);
|
||||
fprintf(out, CONFIG_PREFIX"%s=\"", sym->name);
|
||||
fprintf(out_h, "#define "CONFIG_PREFIX"%s \"", sym->name);
|
||||
while (1) {
|
||||
l = strcspn(str, "\"\\");
|
||||
if (l) {
|
||||
fwrite(str, l, 1, out);
|
||||
fwrite(str, l, 1, out_h);
|
||||
str += l;
|
||||
}
|
||||
if (!*str)
|
||||
break;
|
||||
fprintf(out, "\\%c", *str);
|
||||
fprintf(out_h, "\\%c", *str);
|
||||
str++;
|
||||
}
|
||||
fputs("\"\n", out);
|
||||
fputs("\"\n", out_h);
|
||||
break;
|
||||
case S_HEX:
|
||||
str = sym_get_string_value(sym);
|
||||
if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
|
||||
fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, str);
|
||||
fprintf(out_h, "#define "CONFIG_PREFIX"%s 0x%s\n", sym->name, str);
|
||||
break;
|
||||
}
|
||||
case S_INT:
|
||||
str = sym_get_string_value(sym);
|
||||
fprintf(out, CONFIG_PREFIX"%s=%s\n", sym->name, str);
|
||||
fprintf(out_h, "#define "CONFIG_PREFIX"%s %s\n", sym->name, str);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(out);
|
||||
fclose(out_h);
|
||||
|
||||
name = getenv("KCONFIG_AUTOHEADER");
|
||||
if (!name)
|
||||
name = "include/linux/autoconf.h";
|
||||
if (rename(".tmpconfig.h", name))
|
||||
return 1;
|
||||
name = getenv("KCONFIG_AUTOCONFIG");
|
||||
if (!name)
|
||||
name = "include/config/auto.conf";
|
||||
/*
|
||||
* This must be the last step, kbuild has a dependency on auto.conf
|
||||
* and this marks the successful completion of the previous steps.
|
||||
*/
|
||||
if (rename(".tmpconfig", name))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
+1100
File diff suppressed because it is too large
Load Diff
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
struct file {
|
||||
struct file *next;
|
||||
struct file *parent;
|
||||
char *name;
|
||||
int lineno;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define FILE_BUSY 0x0001
|
||||
#define FILE_SCANNED 0x0002
|
||||
#define FILE_PRINTED 0x0004
|
||||
|
||||
typedef enum tristate {
|
||||
no, mod, yes
|
||||
} tristate;
|
||||
|
||||
enum expr_type {
|
||||
E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, 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 E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
|
||||
#define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
|
||||
#define E_NOT(dep) (2-(dep))
|
||||
|
||||
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 {
|
||||
S_DEF_USER, /* main user value */
|
||||
S_DEF_AUTO,
|
||||
};
|
||||
|
||||
struct symbol {
|
||||
struct symbol *next;
|
||||
char *name;
|
||||
char *help;
|
||||
enum symbol_type type;
|
||||
struct symbol_value curr;
|
||||
struct symbol_value def[4];
|
||||
tristate visible;
|
||||
int flags;
|
||||
struct property *prop;
|
||||
struct expr *dep, *dep2;
|
||||
struct expr_value rev_dep;
|
||||
};
|
||||
|
||||
#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
|
||||
|
||||
#define SYMBOL_CONST 0x0001
|
||||
#define SYMBOL_CHECK 0x0008
|
||||
#define SYMBOL_CHOICE 0x0010
|
||||
#define SYMBOL_CHOICEVAL 0x0020
|
||||
#define SYMBOL_PRINTED 0x0040
|
||||
#define SYMBOL_VALID 0x0080
|
||||
#define SYMBOL_OPTIONAL 0x0100
|
||||
#define SYMBOL_WRITE 0x0200
|
||||
#define SYMBOL_CHANGED 0x0400
|
||||
#define SYMBOL_AUTO 0x1000
|
||||
#define SYMBOL_CHECKED 0x2000
|
||||
#define SYMBOL_WARNED 0x8000
|
||||
#define SYMBOL_DEF 0x10000
|
||||
#define SYMBOL_DEF_USER 0x10000
|
||||
#define SYMBOL_DEF_AUTO 0x20000
|
||||
#define SYMBOL_DEF3 0x40000
|
||||
#define SYMBOL_DEF4 0x80000
|
||||
|
||||
#define SYMBOL_MAXLENGTH 256
|
||||
#define SYMBOL_HASHSIZE 257
|
||||
#define SYMBOL_HASHMASK 0xff
|
||||
|
||||
enum prop_type {
|
||||
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
|
||||
};
|
||||
|
||||
struct property {
|
||||
struct property *next;
|
||||
struct symbol *sym;
|
||||
enum prop_type type;
|
||||
const char *text;
|
||||
struct expr_value visible;
|
||||
struct expr *expr;
|
||||
struct menu *menu;
|
||||
struct file *file;
|
||||
int lineno;
|
||||
};
|
||||
|
||||
#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 *dep;
|
||||
unsigned int flags;
|
||||
//char *help;
|
||||
struct file *file;
|
||||
int lineno;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define MENU_CHANGED 0x0001
|
||||
#define MENU_ROOT 0x0002
|
||||
|
||||
#ifndef SWIG
|
||||
|
||||
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(struct expr *org);
|
||||
void expr_free(struct expr *e);
|
||||
int expr_eq(struct expr *e1, struct expr *e2);
|
||||
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
|
||||
tristate expr_calc_value(struct expr *e);
|
||||
struct expr *expr_eliminate_yn(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_extract_eq_and(struct expr **ep1, struct expr **ep2);
|
||||
struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
|
||||
void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
|
||||
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EXPR_H */
|
||||
@@ -0,0 +1,128 @@
|
||||
CONFIG_BASENAME=y
|
||||
CONFIG_CAL=y
|
||||
CONFIG_CAT=y
|
||||
CONFIG_CATV=y
|
||||
CONFIG_CHGRP=y
|
||||
CONFIG_CHOWN=y
|
||||
CONFIG_CHMOD=y
|
||||
CONFIG_CKSUM=y
|
||||
CONFIG_CRC32=y
|
||||
CONFIG_CMP=y
|
||||
CONFIG_COMM=y
|
||||
CONFIG_CPIO=y
|
||||
CONFIG_CUT=y
|
||||
CONFIG_DATE=y
|
||||
CONFIG_DIRNAME=y
|
||||
CONFIG_DU=y
|
||||
CONFIG_ECHO=y
|
||||
CONFIG_EXPAND=y
|
||||
CONFIG_FALSE=y
|
||||
CONFIG_FILE=y
|
||||
CONFIG_FIND=y
|
||||
CONFIG_GREP=y
|
||||
CONFIG_HEAD=y
|
||||
CONFIG_ICONV=y
|
||||
CONFIG_ID=y
|
||||
CONFIG_GROUPS=y
|
||||
CONFIG_LOGNAME=y
|
||||
CONFIG_WHOAMI=y
|
||||
CONFIG_KILL=y
|
||||
CONFIG_KILLALL5=y
|
||||
CONFIG_LINK=y
|
||||
CONFIG_LN=y
|
||||
CONFIG_LOGGER=y
|
||||
CONFIG_LS=y
|
||||
CONFIG_MKDIR=y
|
||||
CONFIG_MKFIFO=y
|
||||
CONFIG_NICE=y
|
||||
CONFIG_NL=y
|
||||
CONFIG_NOHUP=y
|
||||
CONFIG_OD=y
|
||||
CONFIG_PASTE=y
|
||||
CONFIG_PATCH=y
|
||||
CONFIG_PRINTF=y
|
||||
CONFIG_PWD=y
|
||||
CONFIG_RENICE=y
|
||||
CONFIG_RM=y
|
||||
CONFIG_RMDIR=y
|
||||
CONFIG_SED=y
|
||||
CONFIG_SLEEP=y
|
||||
CONFIG_SORT=y
|
||||
CONFIG_SPLIT=y
|
||||
CONFIG_STRINGS=y
|
||||
CONFIG_TEE=y
|
||||
CONFIG_TEST=y
|
||||
CONFIG_TIME=y
|
||||
CONFIG_TOUCH=y
|
||||
CONFIG_TRUE=y
|
||||
CONFIG_TTY=y
|
||||
CONFIG_UNAME=y
|
||||
CONFIG_UNIQ=y
|
||||
CONFIG_UNLINK=y
|
||||
CONFIG_UUDECODE=y
|
||||
CONFIG_UUENCODE=y
|
||||
CONFIG_WC=y
|
||||
CONFIG_WHO=y
|
||||
CONFIG_XARGS=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_ASCII=y
|
||||
CONFIG_BASE64=y
|
||||
CONFIG_BUNZIP2=y
|
||||
CONFIG_BZCAT=y
|
||||
CONFIG_CHROOT=y
|
||||
CONFIG_CHRT=y
|
||||
CONFIG_CHVT=y
|
||||
CONFIG_CLEAR=y
|
||||
CONFIG_COUNT=y
|
||||
CONFIG_DOS2UNIX=y
|
||||
CONFIG_UNIX2DOS=y
|
||||
CONFIG_FACTOR=y
|
||||
CONFIG_FALLOCATE=y
|
||||
CONFIG_FLOCK=y
|
||||
CONFIG_FMT=y
|
||||
CONFIG_FSYNC=y
|
||||
CONFIG_HELP=y
|
||||
CONFIG_HELP_EXTRAS=y
|
||||
CONFIG_HEXEDIT=y
|
||||
CONFIG_LSMOD=y
|
||||
CONFIG_LSPCI=y
|
||||
CONFIG_LSPCI_TEXT=y
|
||||
CONFIG_LSUSB=y
|
||||
CONFIG_MAKEDEVS=y
|
||||
CONFIG_MKPASSWD=y
|
||||
CONFIG_MKSWAP=y
|
||||
CONFIG_MODINFO=y
|
||||
CONFIG_MOUNTPOINT=y
|
||||
CONFIG_PMAP=y
|
||||
CONFIG_PRINTENV=y
|
||||
CONFIG_PWDX=y
|
||||
CONFIG_READLINK=y
|
||||
CONFIG_REALPATH=y
|
||||
CONFIG_RESET=y
|
||||
CONFIG_REV=y
|
||||
CONFIG_SETSID=y
|
||||
CONFIG_SHRED=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_TAC=y
|
||||
CONFIG_TIMEOUT=y
|
||||
CONFIG_TRUNCATE=y
|
||||
CONFIG_USLEEP=y
|
||||
CONFIG_UUIDGEN=y
|
||||
CONFIG_VMSTAT=y
|
||||
CONFIG_WATCH=y
|
||||
CONFIG_W=y
|
||||
CONFIG_WHICH=y
|
||||
CONFIG_XXD=y
|
||||
CONFIG_YES=y
|
||||
CONFIG_HOSTNAME=y
|
||||
CONFIG_KILLALL=y
|
||||
CONFIG_MKNOD=y
|
||||
CONFIG_MKTEMP=y
|
||||
CONFIG_PIDOF=y
|
||||
CONFIG_SEQ=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_TOYBOX_SUID=y
|
||||
CONFIG_TOYBOX_FLOAT=y
|
||||
CONFIG_TOYBOX_HELP=y
|
||||
CONFIG_TOYBOX_HELP_DASHDASH=y
|
||||
CONFIG_TOYBOX_I18N=y
|
||||
File diff suppressed because it is too large
Load Diff
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
// Make some warnings go away
|
||||
#define YYENABLE_NLS 0
|
||||
#define YYLTYPE_IS_TRIVIAL 0
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
#ifndef KBUILD_NO_NLS
|
||||
# include <libintl.h>
|
||||
#else
|
||||
# define gettext(Msgid) ((const char *) (Msgid))
|
||||
# define textdomain(Domainname) ((const char *) (Domainname))
|
||||
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef LKC_DIRECT_LINK
|
||||
#define P(name,type,arg) extern type name arg
|
||||
#else
|
||||
#include "lkc_defs.h"
|
||||
#define P(name,type,arg) extern type (*name ## _p) arg
|
||||
#endif
|
||||
#include "lkc_proto.h"
|
||||
#undef P
|
||||
|
||||
#define SRCTREE "srctree"
|
||||
|
||||
#define PACKAGE "linux"
|
||||
#define LOCALEDIR "/usr/share/locale"
|
||||
|
||||
#define _(text) gettext(text)
|
||||
#define N_(text) (text)
|
||||
|
||||
|
||||
#define TF_COMMAND 0x0001
|
||||
#define TF_PARAM 0x0002
|
||||
#define TF_OPTION 0x0004
|
||||
|
||||
#define T_OPT_MODULES 1
|
||||
#define T_OPT_DEFCONFIG_LIST 2
|
||||
|
||||
struct kconf_id {
|
||||
int name;
|
||||
int token;
|
||||
unsigned int flags;
|
||||
enum symbol_type stype;
|
||||
};
|
||||
|
||||
int zconfparse(void);
|
||||
void zconfdump(FILE *out);
|
||||
|
||||
extern int zconfdebug;
|
||||
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);
|
||||
char *zconf_curname(void);
|
||||
|
||||
/* confdata.c */
|
||||
char *conf_get_default_confname(void);
|
||||
|
||||
/* kconfig_load.c */
|
||||
void kconfig_load(void);
|
||||
|
||||
/* menu.c */
|
||||
void menu_init(void);
|
||||
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);
|
||||
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);
|
||||
|
||||
struct gstr {
|
||||
size_t len;
|
||||
char *s;
|
||||
};
|
||||
struct gstr str_new(void);
|
||||
struct gstr str_assign(const char *s);
|
||||
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 */
|
||||
void sym_init(void);
|
||||
void sym_clear_all_valid(void);
|
||||
void sym_set_all_changed(void);
|
||||
void sym_set_changed(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);
|
||||
|
||||
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 */
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
/* confdata.c */
|
||||
P(conf_parse,void,(const char *name));
|
||||
P(conf_read,int,(const char *name));
|
||||
P(conf_read_simple,int,(const char *name, int));
|
||||
P(conf_write,int,(const char *name));
|
||||
P(conf_write_autoconf,int,(void));
|
||||
|
||||
/* menu.c */
|
||||
P(rootmenu,struct menu,);
|
||||
|
||||
P(menu_is_visible,bool,(struct menu *menu));
|
||||
P(menu_get_prompt,const char *,(struct menu *menu));
|
||||
P(menu_get_root_menu,struct menu *,(struct menu *menu));
|
||||
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
|
||||
|
||||
/* symbol.c */
|
||||
P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
|
||||
P(sym_change_count,int,);
|
||||
|
||||
P(sym_lookup,struct symbol *,(const char *name, int isconst));
|
||||
P(sym_find,struct symbol *,(const char *name));
|
||||
P(sym_re_search,struct symbol **,(const char *pattern));
|
||||
P(sym_type_name,const char *,(enum symbol_type type));
|
||||
P(sym_calc_value,void,(struct symbol *sym));
|
||||
P(sym_get_type,enum symbol_type,(struct symbol *sym));
|
||||
P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
|
||||
P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
|
||||
P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
|
||||
P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
|
||||
P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
|
||||
P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
|
||||
P(sym_is_changable,bool,(struct symbol *sym));
|
||||
P(sym_get_choice_prop,struct property *,(struct symbol *sym));
|
||||
P(sym_get_default_prop,struct property *,(struct symbol *sym));
|
||||
P(sym_get_string_value,const char *,(struct symbol *sym));
|
||||
|
||||
P(prop_get_type_name,const char *,(enum prop_type type));
|
||||
|
||||
/* expr.c */
|
||||
P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
|
||||
P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
|
||||
@@ -0,0 +1,4 @@
|
||||
This is NOT the official version of dialog. This version has been
|
||||
significantly modified from the original. It is for use by the Linux
|
||||
kernel configuration script. Please do not bother Savio Lam with
|
||||
questions about this program.
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
# Check ncurses compatibility
|
||||
|
||||
# What library to link
|
||||
ldflags()
|
||||
{
|
||||
$cc -print-file-name=libncursesw.so | grep -q /
|
||||
if [ $? -eq 0 ]; then
|
||||
echo '-lncursesw'
|
||||
exit
|
||||
fi
|
||||
$cc -print-file-name=libncurses.so | grep -q /
|
||||
if [ $? -eq 0 ]; then
|
||||
echo '-lncurses'
|
||||
exit
|
||||
fi
|
||||
$cc -print-file-name=libcurses.so | grep -q /
|
||||
if [ $? -eq 0 ]; then
|
||||
echo '-lcurses'
|
||||
exit
|
||||
fi
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Where is ncurses.h?
|
||||
ccflags()
|
||||
{
|
||||
if [ -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="<ncurses/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() {
|
||||
echo "main() {}" | $cc -xc - -o $tmp 2> /dev/null
|
||||
if [ $? != 0 ]; then
|
||||
echo " *** Unable to find the ncurses libraries." 1>&2
|
||||
echo " *** make menuconfig require 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|-header|-library]\n"
|
||||
}
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cc=""
|
||||
case "$1" in
|
||||
"-check")
|
||||
shift
|
||||
cc="$@"
|
||||
check
|
||||
;;
|
||||
"-ccflags")
|
||||
ccflags
|
||||
;;
|
||||
"-ldflags")
|
||||
shift
|
||||
cc="$@"
|
||||
ldflags
|
||||
;;
|
||||
"*")
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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);
|
||||
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
|
||||
|
||||
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
|
||||
mvwaddch(win, choice, item_x, item_str()[0]);
|
||||
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
|
||||
waddstr(win, (char *)item_str() + 1);
|
||||
if (selected) {
|
||||
wmove(win, choice, check_x + 1);
|
||||
wrefresh(win);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, "Select", y, x, selected == 0);
|
||||
print_button(dialog, " 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 + 6))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) < (width + 6))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
max_choice = MIN(list_height, item_count());
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (COLS - width) / 2;
|
||||
y = (LINES - 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 = (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 */
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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 dialog_info {
|
||||
const char *backtitle;
|
||||
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[];
|
||||
|
||||
/*
|
||||
* 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]; /* promtp 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);
|
||||
|
||||
void init_dialog(const char *backtitle);
|
||||
void reset_dialog(void);
|
||||
void end_dialog(void);
|
||||
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);
|
||||
int dialog_textbox(const char *title, const char *file, int height, int width);
|
||||
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);
|
||||
extern char dialog_input_result[];
|
||||
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)
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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, " Ok ", y, x, selected == 0);
|
||||
print_button(dialog, " 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, scroll = 0, key = 0, button = -1;
|
||||
char *instr = dialog_input_result;
|
||||
WINDOW *dialog;
|
||||
|
||||
if (!init)
|
||||
instr[0] = '\0';
|
||||
else
|
||||
strcpy(instr, init);
|
||||
|
||||
do_resize:
|
||||
if (getmaxy(stdscr) <= (height - 2))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) <= (width - 2))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (COLS - width) / 2;
|
||||
y = (LINES - 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.border.atr, dlg.dialog.atr);
|
||||
|
||||
print_buttons(dialog, height, width, 0);
|
||||
|
||||
/* Set up the initial value */
|
||||
wmove(dialog, box_y, box_x);
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
|
||||
input_x = strlen(instr);
|
||||
|
||||
if (input_x >= box_width) {
|
||||
scroll = input_x - box_width + 1;
|
||||
input_x = box_width - 1;
|
||||
for (i = 0; i < box_width - 1; i++)
|
||||
waddch(dialog, instr[scroll + i]);
|
||||
} else {
|
||||
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_LEFT:
|
||||
continue;
|
||||
case KEY_RIGHT:
|
||||
continue;
|
||||
case KEY_BACKSPACE:
|
||||
case 127:
|
||||
if (input_x || scroll) {
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
if (!input_x) {
|
||||
scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width; i++)
|
||||
waddch(dialog,
|
||||
instr[scroll + input_x + i] ?
|
||||
instr[scroll + input_x + i] : ' ');
|
||||
input_x = strlen(instr) - scroll;
|
||||
} else
|
||||
input_x--;
|
||||
instr[scroll + input_x] = '\0';
|
||||
mvwaddch(dialog, box_y, input_x + box_x, ' ');
|
||||
wmove(dialog, box_y, input_x + box_x);
|
||||
wrefresh(dialog);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
if (key < 0x100 && isprint(key)) {
|
||||
if (scroll + input_x < MAX_LEN) {
|
||||
wattrset(dialog, dlg.inputbox.atr);
|
||||
instr[scroll + input_x] = key;
|
||||
instr[scroll + input_x + 1] = '\0';
|
||||
if (input_x == box_width - 1) {
|
||||
scroll++;
|
||||
wmove(dialog, box_y, box_x);
|
||||
for (i = 0; i < box_width - 1; i++)
|
||||
waddch(dialog, instr [scroll + i]);
|
||||
} else {
|
||||
wmove(dialog, box_y, input_x++ + box_x);
|
||||
waddch(dialog, key);
|
||||
}
|
||||
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 "Cancel" 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 "Cancel" 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 */
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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 - 16;
|
||||
int y = height - 2;
|
||||
|
||||
print_button(win, "Select", y, x, selected == 0);
|
||||
print_button(win, " Exit ", y, x + 12, selected == 1);
|
||||
print_button(win, " Help ", y, x + 24, selected == 2);
|
||||
|
||||
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 < 15 || width < 65)
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
height -= 4;
|
||||
width -= 5;
|
||||
menu_height = height - 10;
|
||||
|
||||
max_choice = MIN(menu_height, item_count());
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (COLS - width) / 2;
|
||||
y = (LINES - 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 (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)
|
||||
? 2 : (button > 2 ? 0 : button);
|
||||
|
||||
print_buttons(dialog, height, width, button);
|
||||
wrefresh(menu);
|
||||
break;
|
||||
case ' ':
|
||||
case 's':
|
||||
case 'y':
|
||||
case 'n':
|
||||
case 'm':
|
||||
case '/':
|
||||
/* save scroll info */
|
||||
*s_scroll = scroll;
|
||||
delwin(menu);
|
||||
delwin(dialog);
|
||||
item_set(scroll + choice);
|
||||
item_set_selected(1);
|
||||
switch (key) {
|
||||
case 's':
|
||||
return 3;
|
||||
case 'y':
|
||||
return 3;
|
||||
case 'n':
|
||||
return 4;
|
||||
case 'm':
|
||||
return 5;
|
||||
case ' ':
|
||||
return 6;
|
||||
case '/':
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
case 'h':
|
||||
case '?':
|
||||
button = 2;
|
||||
case '\n':
|
||||
*s_scroll = scroll;
|
||||
delwin(menu);
|
||||
delwin(dialog);
|
||||
item_set(scroll + choice);
|
||||
item_set_selected(1);
|
||||
return button;
|
||||
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 */
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* 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);
|
||||
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 const char *buf;
|
||||
static const char *page;
|
||||
|
||||
/*
|
||||
* refresh window content
|
||||
*/
|
||||
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
|
||||
int cur_y, int cur_x)
|
||||
{
|
||||
print_page(box, boxh, boxw);
|
||||
print_position(dialog);
|
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
|
||||
wrefresh(dialog);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Display text from a file in a dialog box.
|
||||
*/
|
||||
int dialog_textbox(const char *title, const char *tbuf,
|
||||
int initial_height, int initial_width)
|
||||
{
|
||||
int i, x, y, cur_x, cur_y, key = 0;
|
||||
int height, width, boxh, boxw;
|
||||
int passed_end;
|
||||
WINDOW *dialog, *box;
|
||||
|
||||
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 */
|
||||
|
||||
do_resize:
|
||||
getmaxyx(stdscr, height, width);
|
||||
if (height < 8 || width < 8)
|
||||
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 = (COLS - width) / 2;
|
||||
y = (LINES - 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, " 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);
|
||||
|
||||
while ((key != KEY_ESC) && (key != '\n')) {
|
||||
key = wgetch(dialog);
|
||||
switch (key) {
|
||||
case 'E': /* Exit */
|
||||
case 'e':
|
||||
case 'X':
|
||||
case 'x':
|
||||
delwin(box);
|
||||
delwin(dialog);
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
break;
|
||||
case 'K': /* Previous line */
|
||||
case 'k':
|
||||
case KEY_UP:
|
||||
if (!begin_reached) {
|
||||
back_lines(page_length + 1);
|
||||
|
||||
/* We don't call print_page() here but use
|
||||
* scrolling to ensure faster screen update.
|
||||
* However, 'end_reached' and 'page_length'
|
||||
* should still be updated, and 'page' should
|
||||
* point to start of next page. This is done
|
||||
* by calling get_line() in the following
|
||||
* 'for' loop. */
|
||||
scrollok(box, TRUE);
|
||||
wscrl(box, -1); /* Scroll box region down one line */
|
||||
scrollok(box, FALSE);
|
||||
page_length = 0;
|
||||
passed_end = 0;
|
||||
for (i = 0; i < boxh; i++) {
|
||||
if (!i) {
|
||||
/* print first line of page */
|
||||
print_line(box, 0, boxw);
|
||||
wnoutrefresh(box);
|
||||
} else
|
||||
/* Called to update 'end_reached' and 'page' */
|
||||
get_line();
|
||||
if (!passed_end)
|
||||
page_length++;
|
||||
if (end_reached && !passed_end)
|
||||
passed_end = 1;
|
||||
}
|
||||
|
||||
print_position(dialog);
|
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
|
||||
wrefresh(dialog);
|
||||
}
|
||||
break;
|
||||
case 'B': /* Previous page */
|
||||
case 'b':
|
||||
case KEY_PPAGE:
|
||||
if (begin_reached)
|
||||
break;
|
||||
back_lines(page_length + boxh);
|
||||
refresh_text_box(dialog, box, boxh, boxw,
|
||||
cur_y, cur_x);
|
||||
break;
|
||||
case 'J': /* Next line */
|
||||
case 'j':
|
||||
case KEY_DOWN:
|
||||
if (!end_reached) {
|
||||
begin_reached = 0;
|
||||
scrollok(box, TRUE);
|
||||
scroll(box); /* Scroll box region up one line */
|
||||
scrollok(box, FALSE);
|
||||
print_line(box, boxh - 1, boxw);
|
||||
wnoutrefresh(box);
|
||||
print_position(dialog);
|
||||
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
|
||||
wrefresh(dialog);
|
||||
}
|
||||
break;
|
||||
case KEY_NPAGE: /* Next page */
|
||||
case ' ':
|
||||
if (end_reached)
|
||||
break;
|
||||
|
||||
begin_reached = 0;
|
||||
refresh_text_box(dialog, box, boxh, boxw,
|
||||
cur_y, cur_x);
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
key = on_key_esc(dialog);
|
||||
break;
|
||||
case KEY_RESIZE:
|
||||
back_lines(height);
|
||||
delwin(box);
|
||||
delwin(dialog);
|
||||
on_key_resize();
|
||||
goto do_resize;
|
||||
}
|
||||
}
|
||||
delwin(box);
|
||||
delwin(dialog);
|
||||
return key; /* ESC pressed */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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. Called by dialog_textbox().
|
||||
*/
|
||||
static void print_page(WINDOW * win, int height, int width)
|
||||
{
|
||||
int i, passed_end = 0;
|
||||
|
||||
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. Called by dialog_textbox() and print_page().
|
||||
*/
|
||||
static void print_line(WINDOW * win, int row, int width)
|
||||
{
|
||||
int y, x;
|
||||
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));
|
||||
|
||||
getyx(win, y, x);
|
||||
/* Clear 'residue' of previous line */
|
||||
#if OLD_NCURSES
|
||||
{
|
||||
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') {
|
||||
if (!end_reached) {
|
||||
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 pass '\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);
|
||||
}
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* 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 "dialog.h"
|
||||
|
||||
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)
|
||||
{
|
||||
if (set_theme(theme)) {
|
||||
if (has_colors()) { /* Terminal supports color? */
|
||||
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)
|
||||
{
|
||||
attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
|
||||
/* Display background title if it exists ... - SLH */
|
||||
if (dlg.backtitle != NULL) {
|
||||
int i;
|
||||
|
||||
wattrset(stdscr, dlg.screen.atr);
|
||||
mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
|
||||
wmove(stdscr, 1, 1);
|
||||
for (i = 1; i < COLS - 1; i++)
|
||||
waddch(stdscr, ACS_HLINE);
|
||||
}
|
||||
wnoutrefresh(stdscr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do some initialization for dialog
|
||||
*/
|
||||
void init_dialog(const char *backtitle)
|
||||
{
|
||||
dlg.backtitle = backtitle;
|
||||
color_setup(getenv("MENUCONFIG_COLOR"));
|
||||
}
|
||||
|
||||
void reset_dialog(void)
|
||||
{
|
||||
initscr(); /* Init curses */
|
||||
keypad(stdscr, TRUE);
|
||||
cbreak();
|
||||
noecho();
|
||||
dialog_clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* End using dialog functions.
|
||||
*/
|
||||
void end_dialog(void)
|
||||
{
|
||||
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 replaced by spaces. 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 i, prompt_len, room, wlen;
|
||||
char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
|
||||
|
||||
strcpy(tempstr, prompt);
|
||||
|
||||
prompt_len = strlen(tempstr);
|
||||
|
||||
/*
|
||||
* Remove newlines
|
||||
*/
|
||||
for (i = 0; i < prompt_len; i++) {
|
||||
if (tempstr[i] == '\n')
|
||||
tempstr[i] = ' ';
|
||||
}
|
||||
|
||||
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 = index(word, ' ');
|
||||
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 = index(sp, ' '))
|
||||
|| 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);
|
||||
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);
|
||||
}
|
||||
@@ -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, " Yes ", y, x, selected == 0);
|
||||
print_button(dialog, " 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 + 4))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
if (getmaxx(stdscr) < (width + 4))
|
||||
return -ERRDISPLAYTOOSMALL;
|
||||
|
||||
/* center dialog box on screen */
|
||||
x = (COLS - width) / 2;
|
||||
y = (LINES - 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 */
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
CONFIG_BASENAME=y
|
||||
CONFIG_CAL=y
|
||||
CONFIG_CAT=y
|
||||
CONFIG_CAT_V=y
|
||||
CONFIG_CATV=y
|
||||
CONFIG_CHGRP=y
|
||||
CONFIG_CHOWN=y
|
||||
CONFIG_CHMOD=y
|
||||
CONFIG_CKSUM=y
|
||||
CONFIG_CRC32=y
|
||||
CONFIG_CMP=y
|
||||
CONFIG_COMM=y
|
||||
CONFIG_CPIO=y
|
||||
CONFIG_CUT=y
|
||||
CONFIG_DATE=y
|
||||
CONFIG_DIRNAME=y
|
||||
CONFIG_DU=y
|
||||
CONFIG_ECHO=y
|
||||
CONFIG_ENV=y
|
||||
CONFIG_EXPAND=y
|
||||
CONFIG_FALSE=y
|
||||
CONFIG_FILE=y
|
||||
CONFIG_FIND=y
|
||||
CONFIG_GETCONF=y
|
||||
CONFIG_GREP=y
|
||||
CONFIG_HEAD=y
|
||||
CONFIG_ICONV=y
|
||||
CONFIG_ID=y
|
||||
CONFIG_GROUPS=y
|
||||
CONFIG_LOGNAME=y
|
||||
CONFIG_WHOAMI=y
|
||||
CONFIG_KILL=y
|
||||
CONFIG_KILLALL5=y
|
||||
CONFIG_LINK=y
|
||||
CONFIG_LN=y
|
||||
CONFIG_LOGGER=y
|
||||
CONFIG_LS=y
|
||||
CONFIG_MKDIR=y
|
||||
CONFIG_MKFIFO=y
|
||||
CONFIG_NICE=y
|
||||
CONFIG_NL=y
|
||||
CONFIG_NOHUP=y
|
||||
CONFIG_OD=y
|
||||
CONFIG_PASTE=y
|
||||
CONFIG_PATCH=y
|
||||
CONFIG_PRINTF=y
|
||||
CONFIG_PWD=y
|
||||
CONFIG_RENICE=y
|
||||
CONFIG_RM=y
|
||||
CONFIG_RMDIR=y
|
||||
CONFIG_SED=y
|
||||
CONFIG_SLEEP=y
|
||||
CONFIG_SORT=y
|
||||
CONFIG_SPLIT=y
|
||||
CONFIG_STRINGS=y
|
||||
CONFIG_TAR=y
|
||||
CONFIG_TEE=y
|
||||
CONFIG_TEST=y
|
||||
CONFIG_TIME=y
|
||||
CONFIG_TOUCH=y
|
||||
CONFIG_TRUE=y
|
||||
CONFIG_TTY=y
|
||||
CONFIG_UNAME=y
|
||||
CONFIG_UNIQ=y
|
||||
CONFIG_UNLINK=y
|
||||
CONFIG_UUDECODE=y
|
||||
CONFIG_UUENCODE=y
|
||||
CONFIG_WC=y
|
||||
CONFIG_WHO=y
|
||||
CONFIG_XARGS=y
|
||||
CONFIG_ASCII=y
|
||||
CONFIG_BASE64=y
|
||||
CONFIG_CLEAR=y
|
||||
CONFIG_COUNT=y
|
||||
CONFIG_DOS2UNIX=y
|
||||
CONFIG_UNIX2DOS=y
|
||||
CONFIG_FACTOR=y
|
||||
CONFIG_FLOCK=y
|
||||
CONFIG_FMT=y
|
||||
CONFIG_HELP=y
|
||||
CONFIG_HELP_EXTRAS=y
|
||||
CONFIG_HEXEDIT=y
|
||||
CONFIG_PRINTENV=y
|
||||
CONFIG_PWDX=y
|
||||
CONFIG_READLINK=y
|
||||
CONFIG_REALPATH=y
|
||||
CONFIG_REV=y
|
||||
CONFIG_SETSID=y
|
||||
CONFIG_TAC=y
|
||||
CONFIG_TIMEOUT=y
|
||||
CONFIG_TRUNCATE=y
|
||||
CONFIG_USLEEP=y
|
||||
CONFIG_UUIDGEN=y
|
||||
CONFIG_WATCH=y
|
||||
CONFIG_W=y
|
||||
CONFIG_WHICH=y
|
||||
CONFIG_XXD=y
|
||||
CONFIG_YES=y
|
||||
CONFIG_FTPGET=y
|
||||
CONFIG_FTPPUT=y
|
||||
CONFIG_MICROCOM=y
|
||||
CONFIG_NETCAT=y
|
||||
CONFIG_NETCAT_LISTEN=y
|
||||
CONFIG_HOSTNAME=y
|
||||
CONFIG_MD5SUM=y
|
||||
CONFIG_SHA1SUM=y
|
||||
CONFIG_SEQ=y
|
||||
CONFIG_TAIL=y
|
||||
CONFIG_TOYBOX_SUID=y
|
||||
CONFIG_TOYBOX_FLOAT=y
|
||||
CONFIG_TOYBOX_HELP=y
|
||||
CONFIG_TOYBOX_HELP_DASHDASH=y
|
||||
CONFIG_TOYBOX_I18N=y
|
||||
+919
@@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*
|
||||
* Introduced single menu mode (show all sub-menus in one large tree).
|
||||
* 2002-11-06 Petr Baudis <pasky@ucw.cz>
|
||||
*
|
||||
* i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
|
||||
#define LKC_DIRECT_LINK
|
||||
#include "lkc.h"
|
||||
#include "lxdialog/dialog.h"
|
||||
|
||||
static char menu_backtitle[128];
|
||||
static const char mconf_readme[] = N_(
|
||||
"Overview\n"
|
||||
"--------\n"
|
||||
"Some features may be built directly into the project.\n"
|
||||
"Some may be made into loadable runtime modules. Some features\n"
|
||||
"may be completely removed altogether. There are also certain\n"
|
||||
"parameters which are not really features, but must be\n"
|
||||
"entered in as decimal or hexadecimal numbers or possibly text.\n"
|
||||
"\n"
|
||||
"Menu items beginning with [*], <M> or [ ] represent features\n"
|
||||
"configured to be built in, modularized or removed respectively.\n"
|
||||
"Pointed brackets <> represent module capable features.\n"
|
||||
"\n"
|
||||
"To change any of these features, highlight it with the cursor\n"
|
||||
"keys and press <Y> to build it in, <M> to make it a module or\n"
|
||||
"<N> to removed it. You may also press the <Space Bar> to cycle\n"
|
||||
"through the available options (ie. Y->N->M->Y).\n"
|
||||
"\n"
|
||||
"Some additional keyboard hints:\n"
|
||||
"\n"
|
||||
"Menus\n"
|
||||
"----------\n"
|
||||
"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
|
||||
" you wish to change or submenu wish to select and press <Enter>.\n"
|
||||
" Submenus are designated by \"--->\".\n"
|
||||
"\n"
|
||||
" Shortcut: Press the option's highlighted letter (hotkey).\n"
|
||||
" Pressing a hotkey more than once will sequence\n"
|
||||
" through all visible items which use that hotkey.\n"
|
||||
"\n"
|
||||
" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
|
||||
" unseen options into view.\n"
|
||||
"\n"
|
||||
"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
|
||||
" and press <ENTER>.\n"
|
||||
"\n"
|
||||
" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
|
||||
" using those letters. You may press a single <ESC>, but\n"
|
||||
" there is a delayed response which you may find annoying.\n"
|
||||
"\n"
|
||||
" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
|
||||
" <Exit> and <Help>\n"
|
||||
"\n"
|
||||
"o To get help with an item, use the cursor keys to highlight <Help>\n"
|
||||
" and Press <ENTER>.\n"
|
||||
"\n"
|
||||
" Shortcut: Press <H> or <?>.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Radiolists (Choice lists)\n"
|
||||
"-----------\n"
|
||||
"o Use the cursor keys to select the option you wish to set and press\n"
|
||||
" <S> or the <SPACE BAR>.\n"
|
||||
"\n"
|
||||
" Shortcut: Press the first letter of the option you wish to set then\n"
|
||||
" press <S> or <SPACE BAR>.\n"
|
||||
"\n"
|
||||
"o To see available help for the item, use the cursor keys to highlight\n"
|
||||
" <Help> and Press <ENTER>.\n"
|
||||
"\n"
|
||||
" Shortcut: Press <H> or <?>.\n"
|
||||
"\n"
|
||||
" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
|
||||
" <Help>\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Data Entry\n"
|
||||
"-----------\n"
|
||||
"o Enter the requested information and press <ENTER>\n"
|
||||
" If you are entering hexadecimal values, it is not necessary to\n"
|
||||
" add the '0x' prefix to the entry.\n"
|
||||
"\n"
|
||||
"o For help, use the <TAB> or cursor keys to highlight the help option\n"
|
||||
" and press <ENTER>. You can try <TAB><H> as well.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Text Box (Help Window)\n"
|
||||
"--------\n"
|
||||
"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
|
||||
" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
|
||||
" who are familiar with less and lynx.\n"
|
||||
"\n"
|
||||
"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"Alternate Configuration Files\n"
|
||||
"-----------------------------\n"
|
||||
"Menuconfig supports the use of alternate configuration files for\n"
|
||||
"those who, for various reasons, find it necessary to switch\n"
|
||||
"between different configurations.\n"
|
||||
"\n"
|
||||
"At the end of the main menu you will find two options. One is\n"
|
||||
"for saving the current configuration to a file of your choosing.\n"
|
||||
"The other option is for loading a previously saved alternate\n"
|
||||
"configuration.\n"
|
||||
"\n"
|
||||
"Even if you don't use alternate configuration files, but you\n"
|
||||
"find during a Menuconfig session that you have completely messed\n"
|
||||
"up your settings, you may use the \"Load Alternate...\" option to\n"
|
||||
"restore your previously saved settings from \".config\" without\n"
|
||||
"restarting Menuconfig.\n"
|
||||
"\n"
|
||||
"Other information\n"
|
||||
"-----------------\n"
|
||||
"If you use Menuconfig in an XTERM window make sure you have your\n"
|
||||
"$TERM variable set to point to a xterm definition which supports color.\n"
|
||||
"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
|
||||
"display correctly in a RXVT window because rxvt displays only one\n"
|
||||
"intensity of color, bright.\n"
|
||||
"\n"
|
||||
"Menuconfig will display larger menus on screens or xterms which are\n"
|
||||
"set to display more than the standard 25 row by 80 column geometry.\n"
|
||||
"In order for this to work, the \"stty size\" command must be able to\n"
|
||||
"display the screen's current row and column geometry. I STRONGLY\n"
|
||||
"RECOMMEND that you make sure you do NOT have the shell variables\n"
|
||||
"LINES and COLUMNS exported into your environment. Some distributions\n"
|
||||
"export those variables via /etc/profile. Some ncurses programs can\n"
|
||||
"become confused when those variables (LINES & COLUMNS) don't reflect\n"
|
||||
"the true screen size.\n"
|
||||
"\n"
|
||||
"Optional personality available\n"
|
||||
"------------------------------\n"
|
||||
"If you prefer to have all of the options listed in a single\n"
|
||||
"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
|
||||
"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
|
||||
"\n"
|
||||
"make MENUCONFIG_MODE=single_menu menuconfig\n"
|
||||
"\n"
|
||||
"<Enter> will then unroll the appropriate category, or enfold it if it\n"
|
||||
"is already unrolled.\n"
|
||||
"\n"
|
||||
"Note that this mode can eventually be a little more CPU expensive\n"
|
||||
"(especially with a larger number of unrolled categories) than the\n"
|
||||
"default mode.\n"
|
||||
"\n"
|
||||
"Different color themes available\n"
|
||||
"--------------------------------\n"
|
||||
"It is possible to select different color themes using the variable\n"
|
||||
"MENUCONFIG_COLOR. To select a theme use:\n"
|
||||
"\n"
|
||||
"make MENUCONFIG_COLOR=<theme> menuconfig\n"
|
||||
"\n"
|
||||
"Available themes are\n"
|
||||
" mono => selects colors suitable for monochrome displays\n"
|
||||
" blackbg => selects a color scheme with black background\n"
|
||||
" classic => theme with blue background. The classic look\n"
|
||||
" bluetitle => a LCD friendly version of classic. (default)\n"
|
||||
"\n"),
|
||||
menu_instructions[] = N_(
|
||||
"Arrow keys navigate the menu. "
|
||||
"<Enter> selects submenus --->. "
|
||||
"Highlighted letters are hotkeys. "
|
||||
"Pressing <Y> includes, <N> excludes, <M> modularizes features. "
|
||||
"Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
|
||||
"Legend: [*] built-in [ ] excluded <M> module < > module capable"),
|
||||
radiolist_instructions[] = N_(
|
||||
"Use the arrow keys to navigate this window or "
|
||||
"press the hotkey of the item you wish to select "
|
||||
"followed by the <SPACE BAR>. "
|
||||
"Press <?> for additional information about this option."),
|
||||
inputbox_instructions_int[] = N_(
|
||||
"Please enter a decimal value. "
|
||||
"Fractions will not be accepted. "
|
||||
"Use the <TAB> key to move from the input field to the buttons below it."),
|
||||
inputbox_instructions_hex[] = N_(
|
||||
"Please enter a hexadecimal value. "
|
||||
"Use the <TAB> key to move from the input field to the buttons below it."),
|
||||
inputbox_instructions_string[] = N_(
|
||||
"Please enter a string value. "
|
||||
"Use the <TAB> key to move from the input field to the buttons below it."),
|
||||
setmod_text[] = N_(
|
||||
"This feature depends on another which has been configured as a module.\n"
|
||||
"As a result, this feature will be built as a module."),
|
||||
nohelp_text[] = N_(
|
||||
"There is no help available for this option.\n"),
|
||||
load_config_text[] = N_(
|
||||
"Enter the name of the configuration file you wish to load. "
|
||||
"Accept the name shown to restore the configuration you "
|
||||
"last retrieved. Leave blank to abort."),
|
||||
load_config_help[] = N_(
|
||||
"\n"
|
||||
"For various reasons, one may wish to keep several different\n"
|
||||
"configurations available on a single machine.\n"
|
||||
"\n"
|
||||
"If you have saved a previous configuration in a file other than the\n"
|
||||
"default, entering the name of the file here will allow you\n"
|
||||
"to modify that configuration.\n"
|
||||
"\n"
|
||||
"If you are uncertain, then you have probably never used alternate\n"
|
||||
"configuration files. You should therefor leave this blank to abort.\n"),
|
||||
save_config_text[] = N_(
|
||||
"Enter a filename to which this configuration should be saved "
|
||||
"as an alternate. Leave blank to abort."),
|
||||
save_config_help[] = N_(
|
||||
"\n"
|
||||
"For various reasons, one may wish to keep different\n"
|
||||
"configurations available on a single machine.\n"
|
||||
"\n"
|
||||
"Entering a file name here will allow you to later retrieve, modify\n"
|
||||
"and use the current configuration as an alternate to whatever\n"
|
||||
"configuration options you have selected at that time.\n"
|
||||
"\n"
|
||||
"If you are uncertain what all this means then you should probably\n"
|
||||
"leave this blank.\n"),
|
||||
search_help[] = N_(
|
||||
"\n"
|
||||
"Search for CONFIG_ symbols and display their relations.\n"
|
||||
"Regular expressions are allowed.\n"
|
||||
"Example: search for \"^FOO\"\n"
|
||||
"Result:\n"
|
||||
"-----------------------------------------------------------------\n"
|
||||
"Symbol: FOO [=m]\n"
|
||||
"Prompt: Foo bus is used to drive the bar HW\n"
|
||||
"Defined at drivers/pci/Kconfig:47\n"
|
||||
"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
|
||||
"Location:\n"
|
||||
" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
|
||||
" -> PCI support (PCI [=y])\n"
|
||||
" -> PCI access mode (<choice> [=y])\n"
|
||||
"Selects: LIBCRC32\n"
|
||||
"Selected by: BAR\n"
|
||||
"-----------------------------------------------------------------\n"
|
||||
"o The line 'Prompt:' shows the text used in the menu structure for\n"
|
||||
" this CONFIG_ symbol\n"
|
||||
"o The 'Defined at' line tell at what file / line number the symbol\n"
|
||||
" is defined\n"
|
||||
"o The 'Depends on:' line tell what symbols needs to be defined for\n"
|
||||
" this symbol to be visible in the menu (selectable)\n"
|
||||
"o The 'Location:' lines tell where in the menu structure this symbol\n"
|
||||
" is located\n"
|
||||
" A location followed by a [=y] indicate that this is a selectable\n"
|
||||
" menu item - and current value is displayed inside brackets.\n"
|
||||
"o The 'Selects:' line tell what symbol will be automatically\n"
|
||||
" selected if this symbol is selected (y or m)\n"
|
||||
"o The 'Selected by' line tell what symbol has selected this symbol\n"
|
||||
"\n"
|
||||
"Only relevant lines are shown.\n"
|
||||
"\n\n"
|
||||
"Search examples:\n"
|
||||
"Examples: USB => find all CONFIG_ symbols containing USB\n"
|
||||
" ^USB => find all CONFIG_ symbols starting with USB\n"
|
||||
" USB$ => find all CONFIG_ symbols ending with USB\n"
|
||||
"\n");
|
||||
|
||||
static char filename[PATH_MAX+1] = ".config";
|
||||
static int indent;
|
||||
static struct termios ios_org;
|
||||
static int rows = 0, cols = 0;
|
||||
static struct menu *current_menu;
|
||||
static int child_count;
|
||||
static int single_menu_mode;
|
||||
|
||||
static void conf(struct menu *menu);
|
||||
static void conf_choice(struct menu *menu);
|
||||
static void conf_string(struct menu *menu);
|
||||
static void conf_load(void);
|
||||
static void conf_save(void);
|
||||
static void show_textbox(const char *title, const char *text, int r, int c);
|
||||
static void show_helptext(const char *title, const char *text);
|
||||
static void show_help(struct menu *menu);
|
||||
|
||||
static void init_wsize(void)
|
||||
{
|
||||
struct winsize ws;
|
||||
char *env;
|
||||
|
||||
if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
|
||||
rows = ws.ws_row;
|
||||
cols = ws.ws_col;
|
||||
}
|
||||
|
||||
if (!rows) {
|
||||
env = getenv("LINES");
|
||||
if (env)
|
||||
rows = atoi(env);
|
||||
if (!rows)
|
||||
rows = 24;
|
||||
}
|
||||
if (!cols) {
|
||||
env = getenv("COLUMNS");
|
||||
if (env)
|
||||
cols = atoi(env);
|
||||
if (!cols)
|
||||
cols = 80;
|
||||
}
|
||||
|
||||
if (rows < 19 || cols < 80) {
|
||||
fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
|
||||
fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rows -= 4;
|
||||
cols -= 5;
|
||||
}
|
||||
|
||||
static void get_prompt_str(struct gstr *r, struct property *prop)
|
||||
{
|
||||
int i, j;
|
||||
struct menu *submenu[8], *menu;
|
||||
|
||||
str_printf(r, "Prompt: %s\n", prop->text);
|
||||
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");
|
||||
}
|
||||
menu = prop->menu->parent;
|
||||
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
|
||||
submenu[i++] = menu;
|
||||
if (i > 0) {
|
||||
str_printf(r, " Location:\n");
|
||||
for (j = 4; --i >= 0; j += 2) {
|
||||
menu = submenu[i];
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_symbol_str(struct gstr *r, struct symbol *sym)
|
||||
{
|
||||
bool hit;
|
||||
struct property *prop;
|
||||
|
||||
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
|
||||
sym_get_string_value(sym));
|
||||
for_all_prompts(sym, prop)
|
||||
get_prompt_str(r, prop);
|
||||
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");
|
||||
}
|
||||
|
||||
static struct gstr get_relations_str(struct symbol **sym_arr)
|
||||
{
|
||||
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);
|
||||
if (!i)
|
||||
str_append(&res, "No matches found.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
static void search_conf(void)
|
||||
{
|
||||
struct symbol **sym_arr;
|
||||
struct gstr res;
|
||||
int dres;
|
||||
again:
|
||||
dialog_clear();
|
||||
dres = dialog_inputbox(_("Search Configuration Parameter"),
|
||||
_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
|
||||
10, 75, "");
|
||||
switch (dres) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
show_helptext(_("Search Configuration"), search_help);
|
||||
goto again;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
sym_arr = sym_re_search(dialog_input_result);
|
||||
res = get_relations_str(sym_arr);
|
||||
free(sym_arr);
|
||||
show_textbox(_("Search Results"), str_get(&res), 0, 0);
|
||||
str_free(&res);
|
||||
}
|
||||
|
||||
static void build_conf(struct menu *menu)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct property *prop;
|
||||
struct menu *child;
|
||||
int type, tmp, doint = 2;
|
||||
tristate val;
|
||||
char ch;
|
||||
|
||||
if (!menu_is_visible(menu))
|
||||
return;
|
||||
|
||||
sym = menu->sym;
|
||||
prop = menu->prompt;
|
||||
if (!sym) {
|
||||
if (prop && menu != current_menu) {
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
switch (prop->type) {
|
||||
case P_MENU:
|
||||
child_count++;
|
||||
if (single_menu_mode) {
|
||||
item_make("%s%*c%s",
|
||||
menu->data ? "-->" : "++>",
|
||||
indent + 1, ' ', prompt);
|
||||
} else
|
||||
item_make(" %*c%s --->", indent + 1, ' ', prompt);
|
||||
|
||||
item_set_tag('m');
|
||||
item_set_data(menu);
|
||||
if (single_menu_mode && menu->data)
|
||||
goto conf_childs;
|
||||
return;
|
||||
default:
|
||||
if (prompt) {
|
||||
child_count++;
|
||||
item_make("---%*c%s", indent + 1, ' ', prompt);
|
||||
item_set_tag(':');
|
||||
item_set_data(menu);
|
||||
}
|
||||
}
|
||||
} else
|
||||
doint = 0;
|
||||
goto conf_childs;
|
||||
}
|
||||
|
||||
type = sym_get_type(sym);
|
||||
if (sym_is_choice(sym)) {
|
||||
struct symbol *def_sym = sym_get_choice_value(sym);
|
||||
struct menu *def_menu = NULL;
|
||||
|
||||
child_count++;
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (menu_is_visible(child) && child->sym == def_sym)
|
||||
def_menu = child;
|
||||
}
|
||||
|
||||
val = sym_get_tristate_value(sym);
|
||||
if (sym_is_changable(sym)) {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
item_make("[%c]", val == no ? ' ' : '*');
|
||||
break;
|
||||
case S_TRISTATE:
|
||||
switch (val) {
|
||||
case yes: ch = '*'; break;
|
||||
case mod: ch = 'M'; break;
|
||||
default: ch = ' '; break;
|
||||
}
|
||||
item_make("<%c>", ch);
|
||||
break;
|
||||
}
|
||||
item_set_tag('t');
|
||||
item_set_data(menu);
|
||||
} else {
|
||||
item_make(" ");
|
||||
item_set_tag(def_menu ? 't' : ':');
|
||||
item_set_data(menu);
|
||||
}
|
||||
|
||||
item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
|
||||
if (val == yes) {
|
||||
if (def_menu) {
|
||||
item_add_str(" (%s)", menu_get_prompt(def_menu));
|
||||
item_add_str(" --->");
|
||||
if (def_menu->list) {
|
||||
indent += 2;
|
||||
build_conf(def_menu);
|
||||
indent -= 2;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (menu == current_menu) {
|
||||
item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
|
||||
item_set_tag(':');
|
||||
item_set_data(menu);
|
||||
goto conf_childs;
|
||||
}
|
||||
child_count++;
|
||||
val = sym_get_tristate_value(sym);
|
||||
if (sym_is_choice_value(sym) && val == yes) {
|
||||
item_make(" ");
|
||||
item_set_tag(':');
|
||||
item_set_data(menu);
|
||||
} else {
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
if (sym_is_changable(sym))
|
||||
item_make("[%c]", val == no ? ' ' : '*');
|
||||
else
|
||||
item_make("---");
|
||||
item_set_tag('t');
|
||||
item_set_data(menu);
|
||||
break;
|
||||
case S_TRISTATE:
|
||||
switch (val) {
|
||||
case yes: ch = '*'; break;
|
||||
case mod: ch = 'M'; break;
|
||||
default: ch = ' '; break;
|
||||
}
|
||||
if (sym_is_changable(sym))
|
||||
item_make("<%c>", ch);
|
||||
else
|
||||
item_make("---");
|
||||
item_set_tag('t');
|
||||
item_set_data(menu);
|
||||
break;
|
||||
default:
|
||||
tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
|
||||
item_make("(%s)", sym_get_string_value(sym));
|
||||
tmp = indent - tmp + 4;
|
||||
if (tmp < 0)
|
||||
tmp = 0;
|
||||
item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
|
||||
(sym_has_value(sym) || !sym_is_changable(sym)) ?
|
||||
"" : " (NEW)");
|
||||
item_set_tag('s');
|
||||
item_set_data(menu);
|
||||
goto conf_childs;
|
||||
}
|
||||
}
|
||||
item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
|
||||
(sym_has_value(sym) || !sym_is_changable(sym)) ?
|
||||
"" : " (NEW)");
|
||||
if (menu->prompt->type == P_MENU) {
|
||||
item_add_str(" --->");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
conf_childs:
|
||||
indent += doint;
|
||||
for (child = menu->list; child; child = child->next)
|
||||
build_conf(child);
|
||||
indent -= doint;
|
||||
}
|
||||
|
||||
static void conf(struct menu *menu)
|
||||
{
|
||||
struct menu *submenu;
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
struct symbol *sym;
|
||||
struct menu *active_menu = NULL;
|
||||
int res;
|
||||
int s_scroll = 0;
|
||||
|
||||
while (1) {
|
||||
item_reset();
|
||||
current_menu = menu;
|
||||
build_conf(menu);
|
||||
if (!child_count)
|
||||
break;
|
||||
if (menu == &rootmenu) {
|
||||
item_make("--- ");
|
||||
item_set_tag(':');
|
||||
item_make(_(" Load an Alternate Configuration File"));
|
||||
item_set_tag('L');
|
||||
item_make(_(" Save an Alternate Configuration File"));
|
||||
item_set_tag('S');
|
||||
}
|
||||
dialog_clear();
|
||||
res = dialog_menu(prompt ? prompt : _("Main Menu"),
|
||||
_(menu_instructions),
|
||||
active_menu, &s_scroll);
|
||||
if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
|
||||
break;
|
||||
if (!item_activate_selected())
|
||||
continue;
|
||||
if (!item_tag())
|
||||
continue;
|
||||
|
||||
submenu = item_data();
|
||||
active_menu = item_data();
|
||||
if (submenu)
|
||||
sym = submenu->sym;
|
||||
else
|
||||
sym = NULL;
|
||||
|
||||
switch (res) {
|
||||
case 0:
|
||||
switch (item_tag()) {
|
||||
case 'm':
|
||||
if (single_menu_mode)
|
||||
submenu->data = (void *) (long) !submenu->data;
|
||||
else
|
||||
conf(submenu);
|
||||
break;
|
||||
case 't':
|
||||
if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
|
||||
conf_choice(submenu);
|
||||
else if (submenu->prompt->type == P_MENU)
|
||||
conf(submenu);
|
||||
break;
|
||||
case 's':
|
||||
conf_string(submenu);
|
||||
break;
|
||||
case 'L':
|
||||
conf_load();
|
||||
break;
|
||||
case 'S':
|
||||
conf_save();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (sym)
|
||||
show_help(submenu);
|
||||
else
|
||||
show_helptext("README", _(mconf_readme));
|
||||
break;
|
||||
case 3:
|
||||
if (item_is_tag('t')) {
|
||||
if (sym_set_tristate_value(sym, yes))
|
||||
break;
|
||||
if (sym_set_tristate_value(sym, mod))
|
||||
show_textbox(NULL, setmod_text, 6, 74);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (item_is_tag('t'))
|
||||
sym_set_tristate_value(sym, no);
|
||||
break;
|
||||
case 5:
|
||||
if (item_is_tag('t'))
|
||||
sym_set_tristate_value(sym, mod);
|
||||
break;
|
||||
case 6:
|
||||
if (item_is_tag('t'))
|
||||
sym_toggle_tristate_value(sym);
|
||||
else if (item_is_tag('m'))
|
||||
conf(submenu);
|
||||
break;
|
||||
case 7:
|
||||
search_conf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_textbox(const char *title, const char *text, int r, int c)
|
||||
{
|
||||
dialog_clear();
|
||||
dialog_textbox(title, text, r, c);
|
||||
}
|
||||
|
||||
static void show_helptext(const char *title, const char *text)
|
||||
{
|
||||
show_textbox(title, text, 0, 0);
|
||||
}
|
||||
|
||||
static void show_help(struct menu *menu)
|
||||
{
|
||||
struct gstr help = str_new();
|
||||
struct symbol *sym = menu->sym;
|
||||
|
||||
if (sym->help)
|
||||
{
|
||||
if (sym->name) {
|
||||
str_printf(&help, "CONFIG_%s:\n\n", sym->name);
|
||||
str_append(&help, _(sym->help));
|
||||
str_append(&help, "\n");
|
||||
}
|
||||
} else {
|
||||
str_append(&help, nohelp_text);
|
||||
}
|
||||
get_symbol_str(&help, sym);
|
||||
show_helptext(menu_get_prompt(menu), str_get(&help));
|
||||
str_free(&help);
|
||||
}
|
||||
|
||||
static void conf_choice(struct menu *menu)
|
||||
{
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
struct menu *child;
|
||||
struct symbol *active;
|
||||
|
||||
active = sym_get_choice_value(menu->sym);
|
||||
while (1) {
|
||||
int res;
|
||||
int selected;
|
||||
item_reset();
|
||||
|
||||
current_menu = menu;
|
||||
for (child = menu->list; child; child = child->next) {
|
||||
if (!menu_is_visible(child))
|
||||
continue;
|
||||
item_make("%s", menu_get_prompt(child));
|
||||
item_set_data(child);
|
||||
if (child->sym == active)
|
||||
item_set_selected(1);
|
||||
if (child->sym == sym_get_choice_value(menu->sym))
|
||||
item_set_tag('X');
|
||||
}
|
||||
dialog_clear();
|
||||
res = dialog_checklist(prompt ? prompt : _("Main Menu"),
|
||||
_(radiolist_instructions),
|
||||
15, 70, 6);
|
||||
selected = item_activate_selected();
|
||||
switch (res) {
|
||||
case 0:
|
||||
if (selected) {
|
||||
child = item_data();
|
||||
sym_set_tristate_value(child->sym, yes);
|
||||
}
|
||||
return;
|
||||
case 1:
|
||||
if (selected) {
|
||||
child = item_data();
|
||||
show_help(child);
|
||||
active = child->sym;
|
||||
} else
|
||||
show_help(menu);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
return;
|
||||
case -ERRDISPLAYTOOSMALL:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_string(struct menu *menu)
|
||||
{
|
||||
const char *prompt = menu_get_prompt(menu);
|
||||
|
||||
while (1) {
|
||||
int res;
|
||||
char *heading;
|
||||
|
||||
switch (sym_get_type(menu->sym)) {
|
||||
case S_INT:
|
||||
heading = (char *)_(inputbox_instructions_int);
|
||||
break;
|
||||
case S_HEX:
|
||||
heading = (char *)_(inputbox_instructions_hex);
|
||||
break;
|
||||
case S_STRING:
|
||||
heading = (char *)_(inputbox_instructions_string);
|
||||
break;
|
||||
default:
|
||||
heading = "Internal mconf error!";
|
||||
}
|
||||
dialog_clear();
|
||||
res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
|
||||
heading, 10, 75,
|
||||
sym_get_string_value(menu->sym));
|
||||
switch (res) {
|
||||
case 0:
|
||||
if (sym_set_string_value(menu->sym, dialog_input_result))
|
||||
return;
|
||||
show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
|
||||
break;
|
||||
case 1:
|
||||
show_help(menu);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_load(void)
|
||||
{
|
||||
|
||||
while (1) {
|
||||
int res;
|
||||
dialog_clear();
|
||||
res = dialog_inputbox(NULL, load_config_text,
|
||||
11, 55, filename);
|
||||
switch(res) {
|
||||
case 0:
|
||||
if (!dialog_input_result[0])
|
||||
return;
|
||||
if (!conf_read(dialog_input_result))
|
||||
return;
|
||||
show_textbox(NULL, _("File does not exist!"), 5, 38);
|
||||
break;
|
||||
case 1:
|
||||
show_helptext(_("Load Alternate Configuration"), load_config_help);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_save(void)
|
||||
{
|
||||
while (1) {
|
||||
int res;
|
||||
dialog_clear();
|
||||
res = dialog_inputbox(NULL, save_config_text,
|
||||
11, 55, filename);
|
||||
switch(res) {
|
||||
case 0:
|
||||
if (!dialog_input_result[0])
|
||||
return;
|
||||
if (!conf_write(dialog_input_result))
|
||||
return;
|
||||
show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
|
||||
break;
|
||||
case 1:
|
||||
show_helptext(_("Save Alternate Configuration"), save_config_help);
|
||||
break;
|
||||
case KEY_ESC:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void conf_cleanup(void)
|
||||
{
|
||||
tcsetattr(1, TCSAFLUSH, &ios_org);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct symbol *sym;
|
||||
char *mode;
|
||||
int res;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
conf_parse(av[1] ? av[1] : "");
|
||||
conf_read(NULL);
|
||||
|
||||
sym = sym_lookup("KERNELVERSION", 0);
|
||||
sym_calc_value(sym);
|
||||
sprintf(menu_backtitle, _(PROJECT_NAME" v%s Configuration"),
|
||||
sym_get_string_value(sym));
|
||||
|
||||
mode = getenv("MENUCONFIG_MODE");
|
||||
if (mode) {
|
||||
if (!strcasecmp(mode, "single_menu"))
|
||||
single_menu_mode = 1;
|
||||
}
|
||||
|
||||
tcgetattr(1, &ios_org);
|
||||
atexit(conf_cleanup);
|
||||
init_wsize();
|
||||
reset_dialog();
|
||||
init_dialog(menu_backtitle);
|
||||
do {
|
||||
conf(&rootmenu);
|
||||
dialog_clear();
|
||||
res = dialog_yesno(NULL,
|
||||
_("Do you wish to save your "
|
||||
"new "PROJECT_NAME" configuration?\n"
|
||||
"<ESC><ESC> to continue."),
|
||||
6, 60);
|
||||
} while (res == KEY_ESC);
|
||||
end_dialog();
|
||||
if (res == 0) {
|
||||
if (conf_write(NULL)) {
|
||||
fprintf(stderr, _("\n\n"
|
||||
"Error writing "PROJECT_NAME" configuration.\n"
|
||||
"Your configuration changes were NOT saved."
|
||||
"\n\n"));
|
||||
return 1;
|
||||
}
|
||||
printf(_("\n\n"
|
||||
"*** End of "PROJECT_NAME" configuration.\n"
|
||||
"*** Execute 'make' to build, or try 'make help'."
|
||||
"\n\n"));
|
||||
} else {
|
||||
fprintf(stderr, _("\n\n"
|
||||
"Your configuration changes were NOT saved."
|
||||
"\n\n"));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LKC_DIRECT_LINK
|
||||
#include "lkc.h"
|
||||
|
||||
struct menu rootmenu;
|
||||
static struct menu **last_entry_ptr;
|
||||
|
||||
struct file *file_list;
|
||||
struct file *current_file;
|
||||
|
||||
static 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 = malloc(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;
|
||||
}
|
||||
|
||||
void menu_end_entry(void)
|
||||
{
|
||||
}
|
||||
|
||||
struct menu *menu_add_menu(void)
|
||||
{
|
||||
menu_end_entry();
|
||||
last_entry_ptr = ¤t_entry->list;
|
||||
return current_menu = current_entry;
|
||||
}
|
||||
|
||||
void menu_end_menu(void)
|
||||
{
|
||||
last_entry_ptr = ¤t_menu->next;
|
||||
current_menu = current_menu->parent;
|
||||
}
|
||||
|
||||
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, "type of '%s' redefined 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)
|
||||
prop_warn(prop, "prompt redefined");
|
||||
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_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)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
switch (token) {
|
||||
case T_OPT_MODULES:
|
||||
prop = prop_alloc(P_DEFAULT, modules_sym);
|
||||
prop->expr = expr_alloc_symbol(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;
|
||||
}
|
||||
}
|
||||
|
||||
static int menu_range_valid_sym(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));
|
||||
}
|
||||
|
||||
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 '%'"
|
||||
" must be a single symbol", 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)
|
||||
prop_warn(prop,
|
||||
"'select' used by config symbol '%s' "
|
||||
"refer to undefined symbol '%s'",
|
||||
sym->name, sym2->name);
|
||||
else if (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_range_valid_sym(sym, prop->expr->left.sym) ||
|
||||
!menu_range_valid_sym(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)) {
|
||||
/* find the first choice value and find out choice type */
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
if (menu->sym) {
|
||||
current_entry = parent;
|
||||
menu_set_type(menu->sym->type);
|
||||
current_entry = menu;
|
||||
menu_set_type(sym->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
for (menu = parent->list; menu; menu = menu->next) {
|
||||
if (sym && sym_is_choice(sym) && menu->sym) {
|
||||
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_PROMPT && prop->menu != menu) {
|
||||
prop_warn(prop, "choice values "
|
||||
"currently only support a "
|
||||
"single prompt");
|
||||
}
|
||||
if (prop->type == P_DEFAULT)
|
||||
prop_warn(prop, "defaults for choice "
|
||||
"values not supported");
|
||||
}
|
||||
current_entry = menu;
|
||||
menu_set_type(sym->type);
|
||||
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_CHOICE, 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_is_visible(struct menu *menu)
|
||||
{
|
||||
struct menu *child;
|
||||
struct symbol *sym;
|
||||
tristate visible;
|
||||
|
||||
if (!menu->prompt)
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,884 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
||||
* Released under the terms of the GNU GPL v2.0.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define LKC_DIRECT_LINK
|
||||
#include "lkc.h"
|
||||
|
||||
struct symbol symbol_yes = {
|
||||
.name = "y",
|
||||
.curr = { "y", yes },
|
||||
.flags = SYMBOL_CONST|SYMBOL_VALID,
|
||||
}, symbol_mod = {
|
||||
.name = "m",
|
||||
.curr = { "m", mod },
|
||||
.flags = SYMBOL_CONST|SYMBOL_VALID,
|
||||
}, symbol_no = {
|
||||
.name = "n",
|
||||
.curr = { "n", no },
|
||||
.flags = SYMBOL_CONST|SYMBOL_VALID,
|
||||
}, symbol_empty = {
|
||||
.name = "",
|
||||
.curr = { "", no },
|
||||
.flags = SYMBOL_VALID,
|
||||
};
|
||||
|
||||
int sym_change_count;
|
||||
struct symbol *sym_defconfig_list;
|
||||
struct symbol *modules_sym;
|
||||
tristate modules_val;
|
||||
|
||||
void sym_add_default(struct symbol *sym, const char *def)
|
||||
{
|
||||
struct property *prop = prop_alloc(P_DEFAULT, sym);
|
||||
|
||||
prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
|
||||
}
|
||||
|
||||
void sym_init(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct utsname uts;
|
||||
char *p;
|
||||
static bool inited = false;
|
||||
|
||||
if (inited)
|
||||
return;
|
||||
inited = true;
|
||||
|
||||
uname(&uts);
|
||||
|
||||
/*
|
||||
sym = sym_lookup("ARCH", 0);
|
||||
sym->type = S_STRING;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
p = getenv("ARCH");
|
||||
if (p)
|
||||
sym_add_default(sym, p);
|
||||
*/
|
||||
|
||||
sym = sym_lookup("KERNELVERSION", 0);
|
||||
sym->type = S_STRING;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
p = getenv("KERNELVERSION");
|
||||
if (p)
|
||||
sym_add_default(sym, p);
|
||||
|
||||
sym = sym_lookup("UNAME_RELEASE", 0);
|
||||
sym->type = S_STRING;
|
||||
sym->flags |= SYMBOL_AUTO;
|
||||
sym_add_default(sym, uts.release);
|
||||
}
|
||||
|
||||
enum symbol_type sym_get_type(struct symbol *sym)
|
||||
{
|
||||
enum symbol_type type = sym->type;
|
||||
|
||||
if (type == S_TRISTATE) {
|
||||
if (sym_is_choice_value(sym) && sym->visible == yes)
|
||||
type = S_BOOLEAN;
|
||||
else if (modules_val == no)
|
||||
type = S_BOOLEAN;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
const char *sym_type_name(enum symbol_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case S_BOOLEAN:
|
||||
return "boolean";
|
||||
case S_TRISTATE:
|
||||
return "tristate";
|
||||
case S_INT:
|
||||
return "integer";
|
||||
case S_HEX:
|
||||
return "hex";
|
||||
case S_STRING:
|
||||
return "string";
|
||||
case S_UNKNOWN:
|
||||
return "unknown";
|
||||
case S_OTHER:
|
||||
break;
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
struct property *sym_get_choice_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
for_all_choices(sym, prop)
|
||||
return prop;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct property *sym_get_default_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
for_all_defaults(sym, prop) {
|
||||
prop->visible.tri = expr_calc_value(prop->visible.expr);
|
||||
if (prop->visible.tri != no)
|
||||
return prop;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct property *sym_get_range_prop(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
for_all_properties(sym, prop, P_RANGE) {
|
||||
prop->visible.tri = expr_calc_value(prop->visible.expr);
|
||||
if (prop->visible.tri != no)
|
||||
return prop;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sym_get_range_val(struct symbol *sym, int base)
|
||||
{
|
||||
sym_calc_value(sym);
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
base = 10;
|
||||
break;
|
||||
case S_HEX:
|
||||
base = 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return strtol(sym->curr.val, NULL, base);
|
||||
}
|
||||
|
||||
static void sym_validate_range(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
int base, val, val2;
|
||||
char str[64];
|
||||
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
base = 10;
|
||||
break;
|
||||
case S_HEX:
|
||||
base = 16;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return;
|
||||
val = strtol(sym->curr.val, NULL, base);
|
||||
val2 = sym_get_range_val(prop->expr->left.sym, base);
|
||||
if (val >= val2) {
|
||||
val2 = sym_get_range_val(prop->expr->right.sym, base);
|
||||
if (val <= val2)
|
||||
return;
|
||||
}
|
||||
if (sym->type == S_INT)
|
||||
sprintf(str, "%d", val2);
|
||||
else
|
||||
sprintf(str, "0x%x", val2);
|
||||
sym->curr.val = strdup(str);
|
||||
}
|
||||
|
||||
static void sym_calc_visibility(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
tristate tri;
|
||||
|
||||
/* any prompt visible? */
|
||||
tri = no;
|
||||
for_all_prompts(sym, prop) {
|
||||
prop->visible.tri = expr_calc_value(prop->visible.expr);
|
||||
tri = E_OR(tri, prop->visible.tri);
|
||||
}
|
||||
if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
|
||||
tri = yes;
|
||||
if (sym->visible != tri) {
|
||||
sym->visible = tri;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
if (sym_is_choice_value(sym))
|
||||
return;
|
||||
tri = no;
|
||||
if (sym->rev_dep.expr)
|
||||
tri = expr_calc_value(sym->rev_dep.expr);
|
||||
if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||
tri = yes;
|
||||
if (sym->rev_dep.tri != tri) {
|
||||
sym->rev_dep.tri = tri;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
}
|
||||
|
||||
static struct symbol *sym_calc_choice(struct symbol *sym)
|
||||
{
|
||||
struct symbol *def_sym;
|
||||
struct property *prop;
|
||||
struct expr *e;
|
||||
|
||||
/* is the user choice visible? */
|
||||
def_sym = sym->def[S_DEF_USER].val;
|
||||
if (def_sym) {
|
||||
sym_calc_visibility(def_sym);
|
||||
if (def_sym->visible != no)
|
||||
return def_sym;
|
||||
}
|
||||
|
||||
/* any of the defaults visible? */
|
||||
for_all_defaults(sym, prop) {
|
||||
prop->visible.tri = expr_calc_value(prop->visible.expr);
|
||||
if (prop->visible.tri == no)
|
||||
continue;
|
||||
def_sym = prop_get_symbol(prop);
|
||||
sym_calc_visibility(def_sym);
|
||||
if (def_sym->visible != no)
|
||||
return def_sym;
|
||||
}
|
||||
|
||||
/* just get the first visible value */
|
||||
prop = sym_get_choice_prop(sym);
|
||||
for (e = prop->expr; e; e = e->left.expr) {
|
||||
def_sym = e->right.sym;
|
||||
sym_calc_visibility(def_sym);
|
||||
if (def_sym->visible != no)
|
||||
return def_sym;
|
||||
}
|
||||
|
||||
/* no choice? reset tristate value */
|
||||
sym->curr.tri = no;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sym_calc_value(struct symbol *sym)
|
||||
{
|
||||
struct symbol_value newval, oldval;
|
||||
struct property *prop;
|
||||
struct expr *e;
|
||||
|
||||
if (!sym)
|
||||
return;
|
||||
|
||||
if (sym->flags & SYMBOL_VALID)
|
||||
return;
|
||||
sym->flags |= SYMBOL_VALID;
|
||||
|
||||
oldval = sym->curr;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_INT:
|
||||
case S_HEX:
|
||||
case S_STRING:
|
||||
newval = symbol_empty.curr;
|
||||
break;
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
newval = symbol_no.curr;
|
||||
break;
|
||||
default:
|
||||
sym->curr.val = sym->name;
|
||||
sym->curr.tri = no;
|
||||
return;
|
||||
}
|
||||
if (!sym_is_choice_value(sym))
|
||||
sym->flags &= ~SYMBOL_WRITE;
|
||||
|
||||
sym_calc_visibility(sym);
|
||||
|
||||
/* set default if recursively called */
|
||||
sym->curr = newval;
|
||||
|
||||
switch (sym_get_type(sym)) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
if (sym_is_choice_value(sym) && sym->visible == yes) {
|
||||
prop = sym_get_choice_prop(sym);
|
||||
newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
|
||||
} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
if (sym_has_value(sym))
|
||||
newval.tri = sym->def[S_DEF_USER].tri;
|
||||
else if (!sym_is_choice(sym)) {
|
||||
prop = sym_get_default_prop(sym);
|
||||
if (prop)
|
||||
newval.tri = expr_calc_value(prop->expr);
|
||||
}
|
||||
newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
|
||||
} else if (!sym_is_choice(sym)) {
|
||||
prop = sym_get_default_prop(sym);
|
||||
if (prop) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
newval.tri = expr_calc_value(prop->expr);
|
||||
}
|
||||
}
|
||||
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
||||
newval.tri = yes;
|
||||
break;
|
||||
case S_STRING:
|
||||
case S_HEX:
|
||||
case S_INT:
|
||||
if (sym->visible != no) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
if (sym_has_value(sym)) {
|
||||
newval.val = sym->def[S_DEF_USER].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop = sym_get_default_prop(sym);
|
||||
if (prop) {
|
||||
struct symbol *ds = prop_get_symbol(prop);
|
||||
if (ds) {
|
||||
sym->flags |= SYMBOL_WRITE;
|
||||
sym_calc_value(ds);
|
||||
newval.val = ds->curr.val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
sym->curr = newval;
|
||||
if (sym_is_choice(sym) && newval.tri == yes)
|
||||
sym->curr.val = sym_calc_choice(sym);
|
||||
sym_validate_range(sym);
|
||||
|
||||
if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
|
||||
sym_set_changed(sym);
|
||||
if (modules_sym == sym) {
|
||||
sym_set_all_changed();
|
||||
modules_val = modules_sym->curr.tri;
|
||||
}
|
||||
}
|
||||
|
||||
if (sym_is_choice(sym)) {
|
||||
int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
|
||||
prop = sym_get_choice_prop(sym);
|
||||
for (e = prop->expr; e; e = e->left.expr) {
|
||||
e->right.sym->flags |= flags;
|
||||
if (flags & SYMBOL_CHANGED)
|
||||
sym_set_changed(e->right.sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sym_clear_all_valid(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int i;
|
||||
|
||||
for_all_symbols(i, sym)
|
||||
sym->flags &= ~SYMBOL_VALID;
|
||||
sym_change_count++;
|
||||
if (modules_sym)
|
||||
sym_calc_value(modules_sym);
|
||||
}
|
||||
|
||||
void sym_set_changed(struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
|
||||
sym->flags |= SYMBOL_CHANGED;
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
if (prop->menu)
|
||||
prop->menu->flags |= MENU_CHANGED;
|
||||
}
|
||||
}
|
||||
|
||||
void sym_set_all_changed(void)
|
||||
{
|
||||
struct symbol *sym;
|
||||
int i;
|
||||
|
||||
for_all_symbols(i, sym)
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
|
||||
bool sym_tristate_within_range(struct symbol *sym, tristate val)
|
||||
{
|
||||
int type = sym_get_type(sym);
|
||||
|
||||
if (sym->visible == no)
|
||||
return false;
|
||||
|
||||
if (type != S_BOOLEAN && type != S_TRISTATE)
|
||||
return false;
|
||||
|
||||
if (type == S_BOOLEAN && val == mod)
|
||||
return false;
|
||||
if (sym->visible <= sym->rev_dep.tri)
|
||||
return false;
|
||||
if (sym_is_choice_value(sym) && sym->visible == yes)
|
||||
return val == yes;
|
||||
return val >= sym->rev_dep.tri && val <= sym->visible;
|
||||
}
|
||||
|
||||
bool sym_set_tristate_value(struct symbol *sym, tristate val)
|
||||
{
|
||||
tristate oldval = sym_get_tristate_value(sym);
|
||||
|
||||
if (oldval != val && !sym_tristate_within_range(sym, val))
|
||||
return false;
|
||||
|
||||
if (!(sym->flags & SYMBOL_DEF_USER)) {
|
||||
sym->flags |= SYMBOL_DEF_USER;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
/*
|
||||
* setting a choice value also resets the new flag of the choice
|
||||
* symbol and all other choice values.
|
||||
*/
|
||||
if (sym_is_choice_value(sym) && val == yes) {
|
||||
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
|
||||
struct property *prop;
|
||||
struct expr *e;
|
||||
|
||||
cs->def[S_DEF_USER].val = sym;
|
||||
cs->flags |= SYMBOL_DEF_USER;
|
||||
prop = sym_get_choice_prop(cs);
|
||||
for (e = prop->expr; e; e = e->left.expr) {
|
||||
if (e->right.sym->visible != no)
|
||||
e->right.sym->flags |= SYMBOL_DEF_USER;
|
||||
}
|
||||
}
|
||||
|
||||
sym->def[S_DEF_USER].tri = val;
|
||||
if (oldval != val)
|
||||
sym_clear_all_valid();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tristate sym_toggle_tristate_value(struct symbol *sym)
|
||||
{
|
||||
tristate oldval, newval;
|
||||
|
||||
oldval = newval = sym_get_tristate_value(sym);
|
||||
do {
|
||||
switch (newval) {
|
||||
case no:
|
||||
newval = mod;
|
||||
break;
|
||||
case mod:
|
||||
newval = yes;
|
||||
break;
|
||||
case yes:
|
||||
newval = no;
|
||||
break;
|
||||
}
|
||||
if (sym_set_tristate_value(sym, newval))
|
||||
break;
|
||||
} while (oldval != newval);
|
||||
return newval;
|
||||
}
|
||||
|
||||
bool sym_string_valid(struct symbol *sym, const char *str)
|
||||
{
|
||||
signed char ch;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_STRING:
|
||||
return true;
|
||||
case S_INT:
|
||||
ch = *str++;
|
||||
if (ch == '-')
|
||||
ch = *str++;
|
||||
if (!isdigit(ch))
|
||||
return false;
|
||||
if (ch == '0' && *str != 0)
|
||||
return false;
|
||||
while ((ch = *str++)) {
|
||||
if (!isdigit(ch))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case S_HEX:
|
||||
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
|
||||
str += 2;
|
||||
ch = *str++;
|
||||
do {
|
||||
if (!isxdigit(ch))
|
||||
return false;
|
||||
} while ((ch = *str++));
|
||||
return true;
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (str[0]) {
|
||||
case 'y': case 'Y':
|
||||
case 'm': case 'M':
|
||||
case 'n': case 'N':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sym_string_within_range(struct symbol *sym, const char *str)
|
||||
{
|
||||
struct property *prop;
|
||||
int val;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_STRING:
|
||||
return sym_string_valid(sym, str);
|
||||
case S_INT:
|
||||
if (!sym_string_valid(sym, str))
|
||||
return false;
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return true;
|
||||
val = strtol(str, NULL, 10);
|
||||
return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
|
||||
val <= sym_get_range_val(prop->expr->right.sym, 10);
|
||||
case S_HEX:
|
||||
if (!sym_string_valid(sym, str))
|
||||
return false;
|
||||
prop = sym_get_range_prop(sym);
|
||||
if (!prop)
|
||||
return true;
|
||||
val = strtol(str, NULL, 16);
|
||||
return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
|
||||
val <= sym_get_range_val(prop->expr->right.sym, 16);
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (str[0]) {
|
||||
case 'y': case 'Y':
|
||||
return sym_tristate_within_range(sym, yes);
|
||||
case 'm': case 'M':
|
||||
return sym_tristate_within_range(sym, mod);
|
||||
case 'n': case 'N':
|
||||
return sym_tristate_within_range(sym, no);
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sym_set_string_value(struct symbol *sym, const char *newval)
|
||||
{
|
||||
const char *oldval;
|
||||
char *val;
|
||||
int size;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
switch (newval[0]) {
|
||||
case 'y': case 'Y':
|
||||
return sym_set_tristate_value(sym, yes);
|
||||
case 'm': case 'M':
|
||||
return sym_set_tristate_value(sym, mod);
|
||||
case 'n': case 'N':
|
||||
return sym_set_tristate_value(sym, no);
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
if (!sym_string_within_range(sym, newval))
|
||||
return false;
|
||||
|
||||
if (!(sym->flags & SYMBOL_DEF_USER)) {
|
||||
sym->flags |= SYMBOL_DEF_USER;
|
||||
sym_set_changed(sym);
|
||||
}
|
||||
|
||||
oldval = sym->def[S_DEF_USER].val;
|
||||
size = strlen(newval) + 1;
|
||||
if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
|
||||
size += 2;
|
||||
sym->def[S_DEF_USER].val = val = malloc(size);
|
||||
*val++ = '0';
|
||||
*val++ = 'x';
|
||||
} else if (!oldval || strcmp(oldval, newval))
|
||||
sym->def[S_DEF_USER].val = val = malloc(size);
|
||||
else
|
||||
return true;
|
||||
|
||||
strcpy(val, newval);
|
||||
free((void *)oldval);
|
||||
sym_clear_all_valid();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *sym_get_string_value(struct symbol *sym)
|
||||
{
|
||||
tristate val;
|
||||
|
||||
switch (sym->type) {
|
||||
case S_BOOLEAN:
|
||||
case S_TRISTATE:
|
||||
val = sym_get_tristate_value(sym);
|
||||
switch (val) {
|
||||
case no:
|
||||
return "n";
|
||||
case mod:
|
||||
return "m";
|
||||
case yes:
|
||||
return "y";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return (const char *)sym->curr.val;
|
||||
}
|
||||
|
||||
bool sym_is_changable(struct symbol *sym)
|
||||
{
|
||||
return sym->visible > sym->rev_dep.tri;
|
||||
}
|
||||
|
||||
struct symbol *sym_lookup(const char *name, int isconst)
|
||||
{
|
||||
struct symbol *symbol;
|
||||
const char *ptr;
|
||||
char *new_name;
|
||||
int hash = 0;
|
||||
|
||||
if (name) {
|
||||
if (name[0] && !name[1]) {
|
||||
switch (name[0]) {
|
||||
case 'y': return &symbol_yes;
|
||||
case 'm': return &symbol_mod;
|
||||
case 'n': return &symbol_no;
|
||||
}
|
||||
}
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
hash += *ptr;
|
||||
hash &= 0xff;
|
||||
|
||||
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
|
||||
if (!strcmp(symbol->name, name)) {
|
||||
if ((isconst && symbol->flags & SYMBOL_CONST) ||
|
||||
(!isconst && !(symbol->flags & SYMBOL_CONST)))
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
new_name = strdup(name);
|
||||
} else {
|
||||
new_name = NULL;
|
||||
hash = 256;
|
||||
}
|
||||
|
||||
symbol = malloc(sizeof(*symbol));
|
||||
memset(symbol, 0, sizeof(*symbol));
|
||||
symbol->name = new_name;
|
||||
symbol->type = S_UNKNOWN;
|
||||
if (isconst)
|
||||
symbol->flags |= SYMBOL_CONST;
|
||||
|
||||
symbol->next = symbol_hash[hash];
|
||||
symbol_hash[hash] = symbol;
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
struct symbol *sym_find(const char *name)
|
||||
{
|
||||
struct symbol *symbol = NULL;
|
||||
const char *ptr;
|
||||
int hash = 0;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
if (name[0] && !name[1]) {
|
||||
switch (name[0]) {
|
||||
case 'y': return &symbol_yes;
|
||||
case 'm': return &symbol_mod;
|
||||
case 'n': return &symbol_no;
|
||||
}
|
||||
}
|
||||
for (ptr = name; *ptr; ptr++)
|
||||
hash += *ptr;
|
||||
hash &= 0xff;
|
||||
|
||||
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
|
||||
if (!strcmp(symbol->name, name) &&
|
||||
!(symbol->flags & SYMBOL_CONST))
|
||||
break;
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
struct symbol **sym_re_search(const char *pattern)
|
||||
{
|
||||
struct symbol *sym, **sym_arr = NULL;
|
||||
int i, cnt, size;
|
||||
regex_t re;
|
||||
|
||||
cnt = size = 0;
|
||||
/* Skip if empty */
|
||||
if (strlen(pattern) == 0)
|
||||
return NULL;
|
||||
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
|
||||
return NULL;
|
||||
|
||||
for_all_symbols(i, sym) {
|
||||
if (sym->flags & SYMBOL_CONST || !sym->name)
|
||||
continue;
|
||||
if (regexec(&re, sym->name, 0, NULL, 0))
|
||||
continue;
|
||||
if (cnt + 1 >= size) {
|
||||
void *tmp = sym_arr;
|
||||
size += 16;
|
||||
sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
|
||||
if (!sym_arr) {
|
||||
free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
sym_arr[cnt++] = sym;
|
||||
}
|
||||
if (sym_arr)
|
||||
sym_arr[cnt] = NULL;
|
||||
regfree(&re);
|
||||
|
||||
return sym_arr;
|
||||
}
|
||||
|
||||
|
||||
struct symbol *sym_check_deps(struct symbol *sym);
|
||||
|
||||
static struct symbol *sym_check_expr_deps(struct expr *e)
|
||||
{
|
||||
struct symbol *sym;
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
switch (e->type) {
|
||||
case E_OR:
|
||||
case E_AND:
|
||||
sym = sym_check_expr_deps(e->left.expr);
|
||||
if (sym)
|
||||
return sym;
|
||||
return sym_check_expr_deps(e->right.expr);
|
||||
case E_NOT:
|
||||
return sym_check_expr_deps(e->left.expr);
|
||||
case E_EQUAL:
|
||||
case E_UNEQUAL:
|
||||
sym = sym_check_deps(e->left.sym);
|
||||
if (sym)
|
||||
return sym;
|
||||
return sym_check_deps(e->right.sym);
|
||||
case E_SYMBOL:
|
||||
return sym_check_deps(e->left.sym);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("Oops! How to check %d?\n", e->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct symbol *sym_check_deps(struct symbol *sym)
|
||||
{
|
||||
struct symbol *sym2;
|
||||
struct property *prop;
|
||||
|
||||
if (sym->flags & SYMBOL_CHECK) {
|
||||
printf("Warning! Found recursive dependency: %s", sym->name);
|
||||
return sym;
|
||||
}
|
||||
if (sym->flags & SYMBOL_CHECKED)
|
||||
return NULL;
|
||||
|
||||
sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
|
||||
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
|
||||
for (prop = sym->prop; prop; prop = prop->next) {
|
||||
if (prop->type == P_CHOICE || prop->type == P_SELECT)
|
||||
continue;
|
||||
sym2 = sym_check_expr_deps(prop->visible.expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
if (prop->type != P_DEFAULT || sym_is_choice(sym))
|
||||
continue;
|
||||
sym2 = sym_check_expr_deps(prop->expr);
|
||||
if (sym2)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
if (sym2) {
|
||||
printf(" %s", sym->name);
|
||||
if (sym2 == sym) {
|
||||
printf("\n");
|
||||
sym2 = NULL;
|
||||
}
|
||||
}
|
||||
sym->flags &= ~SYMBOL_CHECK;
|
||||
return sym2;
|
||||
}
|
||||
|
||||
struct property *prop_alloc(enum prop_type type, struct symbol *sym)
|
||||
{
|
||||
struct property *prop;
|
||||
struct property **propp;
|
||||
|
||||
prop = malloc(sizeof(*prop));
|
||||
memset(prop, 0, sizeof(*prop));
|
||||
prop->type = type;
|
||||
prop->sym = sym;
|
||||
prop->file = current_file;
|
||||
prop->lineno = zconf_lineno();
|
||||
|
||||
/* append property to the prop list of symbol */
|
||||
if (sym) {
|
||||
for (propp = &sym->prop; *propp; propp = &(*propp)->next)
|
||||
;
|
||||
*propp = prop;
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
struct symbol *prop_get_symbol(struct property *prop)
|
||||
{
|
||||
if (prop->expr && (prop->expr->type == E_SYMBOL ||
|
||||
prop->expr->type == E_CHOICE))
|
||||
return prop->expr->left.sym;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *prop_get_type_name(enum prop_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case P_PROMPT:
|
||||
return "prompt";
|
||||
case P_COMMENT:
|
||||
return "comment";
|
||||
case P_MENU:
|
||||
return "menu";
|
||||
case P_DEFAULT:
|
||||
return "default";
|
||||
case P_CHOICE:
|
||||
return "choice";
|
||||
case P_SELECT:
|
||||
return "select";
|
||||
case P_RANGE:
|
||||
return "range";
|
||||
case P_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 <string.h>
|
||||
#include "lkc.h"
|
||||
|
||||
/* file already present in list? If not add it */
|
||||
struct file *file_lookup(const char *name)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
for (file = file_list; file; file = file->next) {
|
||||
if (!strcmp(name, file->name))
|
||||
return file;
|
||||
}
|
||||
|
||||
file = malloc(sizeof(*file));
|
||||
memset(file, 0, sizeof(*file));
|
||||
file->name = strdup(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 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, "\ninclude/config/auto.conf: \\\n"
|
||||
"\t$(deps_config)\n\n"
|
||||
"$(deps_config): ;\n");
|
||||
fclose(out);
|
||||
rename("..config.tmp", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate initial growable sting */
|
||||
struct gstr str_new(void)
|
||||
{
|
||||
struct gstr gs;
|
||||
gs.s = malloc(sizeof(char) * 64);
|
||||
gs.len = 16;
|
||||
strcpy(gs.s, "\0");
|
||||
return gs;
|
||||
}
|
||||
|
||||
/* Allocate and assign growable string */
|
||||
struct gstr str_assign(const char *s)
|
||||
{
|
||||
struct gstr gs;
|
||||
gs.s = strdup(s);
|
||||
gs.len = strlen(s) + 1;
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/* ANSI-C code produced by gperf version 3.0.1 */
|
||||
/* 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 = 45, 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[] =
|
||||
{
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 25, 30, 15,
|
||||
0, 15, 0, 47, 5, 15, 47, 47, 30, 20,
|
||||
5, 0, 25, 15, 0, 0, 10, 35, 47, 47,
|
||||
5, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
|
||||
47, 47, 47, 47, 47, 47
|
||||
};
|
||||
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_str6[sizeof("string")];
|
||||
char kconf_id_strings_str7[sizeof("default")];
|
||||
char kconf_id_strings_str8[sizeof("def_bool")];
|
||||
char kconf_id_strings_str10[sizeof("range")];
|
||||
char kconf_id_strings_str11[sizeof("def_boolean")];
|
||||
char kconf_id_strings_str12[sizeof("def_tristate")];
|
||||
char kconf_id_strings_str13[sizeof("hex")];
|
||||
char kconf_id_strings_str14[sizeof("defconfig_list")];
|
||||
char kconf_id_strings_str16[sizeof("option")];
|
||||
char kconf_id_strings_str17[sizeof("if")];
|
||||
char kconf_id_strings_str18[sizeof("optional")];
|
||||
char kconf_id_strings_str20[sizeof("endif")];
|
||||
char kconf_id_strings_str21[sizeof("choice")];
|
||||
char kconf_id_strings_str22[sizeof("endmenu")];
|
||||
char kconf_id_strings_str23[sizeof("requires")];
|
||||
char kconf_id_strings_str24[sizeof("endchoice")];
|
||||
char kconf_id_strings_str26[sizeof("config")];
|
||||
char kconf_id_strings_str27[sizeof("modules")];
|
||||
char kconf_id_strings_str28[sizeof("int")];
|
||||
char kconf_id_strings_str29[sizeof("menu")];
|
||||
char kconf_id_strings_str31[sizeof("prompt")];
|
||||
char kconf_id_strings_str32[sizeof("depends")];
|
||||
char kconf_id_strings_str33[sizeof("tristate")];
|
||||
char kconf_id_strings_str34[sizeof("bool")];
|
||||
char kconf_id_strings_str35[sizeof("menuconfig")];
|
||||
char kconf_id_strings_str36[sizeof("select")];
|
||||
char kconf_id_strings_str37[sizeof("boolean")];
|
||||
char kconf_id_strings_str39[sizeof("help")];
|
||||
char kconf_id_strings_str41[sizeof("source")];
|
||||
char kconf_id_strings_str42[sizeof("comment")];
|
||||
char kconf_id_strings_str43[sizeof("mainmenu")];
|
||||
char kconf_id_strings_str46[sizeof("enable")];
|
||||
};
|
||||
static struct kconf_id_strings_t kconf_id_strings_contents =
|
||||
{
|
||||
"on",
|
||||
"string",
|
||||
"default",
|
||||
"def_bool",
|
||||
"range",
|
||||
"def_boolean",
|
||||
"def_tristate",
|
||||
"hex",
|
||||
"defconfig_list",
|
||||
"option",
|
||||
"if",
|
||||
"optional",
|
||||
"endif",
|
||||
"choice",
|
||||
"endmenu",
|
||||
"requires",
|
||||
"endchoice",
|
||||
"config",
|
||||
"modules",
|
||||
"int",
|
||||
"menu",
|
||||
"prompt",
|
||||
"depends",
|
||||
"tristate",
|
||||
"bool",
|
||||
"menuconfig",
|
||||
"select",
|
||||
"boolean",
|
||||
"help",
|
||||
"source",
|
||||
"comment",
|
||||
"mainmenu",
|
||||
"enable"
|
||||
};
|
||||
#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
|
||||
struct kconf_id *
|
||||
kconf_id_lookup (register const char *str, register unsigned int len)
|
||||
{
|
||||
enum
|
||||
{
|
||||
TOTAL_KEYWORDS = 33,
|
||||
MIN_WORD_LENGTH = 2,
|
||||
MAX_WORD_LENGTH = 14,
|
||||
MIN_HASH_VALUE = 2,
|
||||
MAX_HASH_VALUE = 46
|
||||
};
|
||||
|
||||
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}, {-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_TYPE, TF_COMMAND, S_STRING},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
|
||||
{-1},
|
||||
{(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_DEFAULT, TF_COMMAND, S_BOOLEAN},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_TYPE, TF_COMMAND, S_HEX},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_OPTION, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_IF, TF_COMMAND|TF_PARAM},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_ENDIF, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CHOICE, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_REQUIRES, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str24, T_ENDCHOICE, TF_COMMAND},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_CONFIG, 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_INT},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_PROMPT, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_DEPENDS, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_TRISTATE},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_SELECT, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_HELP, TF_COMMAND},
|
||||
{-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_COMMENT, TF_COMMAND},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_MAINMENU, TF_COMMAND},
|
||||
{-1}, {-1},
|
||||
{(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_SELECT, 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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+504
@@ -0,0 +1,504 @@
|
||||
/* args.c - Command line argument parsing.
|
||||
*
|
||||
* Copyright 2006 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
// NOTE: If option parsing segfaults, switch on TOYBOX_DEBUG in menuconfig to
|
||||
// add syntax checks to option string parsing which aren't needed in the final
|
||||
// code (since get_opt string is hardwired and should be correct when you ship)
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// Design goals:
|
||||
// Don't use getopt() out of libc.
|
||||
// Don't permute original arguments (screwing up ps/top output).
|
||||
// Integrated --long options "(noshort)a(along)b(blong1)(blong2)"
|
||||
|
||||
/* This uses a getopt-like option string, but not getopt() itself. We call
|
||||
* it the get_opt string.
|
||||
*
|
||||
* Each option in the get_opt string corresponds to a bit position in the
|
||||
* return value. The rightmost argument is (1<<0), the next to last is (1<<1)
|
||||
* and so on. If the option isn't seen in argv[], its bit remains 0.
|
||||
*
|
||||
* Options which have an argument fill in the corresponding slot in the global
|
||||
* union "this" (see generated/globals.h), which it treats as an array of longs
|
||||
* (note that sizeof(long)==sizeof(pointer) is guaranteed by LP64).
|
||||
*
|
||||
* You don't have to free the option strings, which point into the environment
|
||||
* space. List objects should be freed by main() when command_main() returns.
|
||||
*
|
||||
* Example:
|
||||
* Calling get_optflags() when toys.which->options="ab:c:d" and
|
||||
* argv = ["command", "-b", "fruit", "-d", "walrus"] results in:
|
||||
*
|
||||
* Changes to struct toys:
|
||||
* toys.optflags = 5 (I.E. 0101 so -b = 4 | -d = 1)
|
||||
* toys.optargs[0] = "walrus" (leftover argument)
|
||||
* toys.optargs[1] = NULL (end of list)
|
||||
* toys.optc = 1 (there was 1 leftover argument)
|
||||
*
|
||||
* Changes to union this:
|
||||
* this[0]=NULL (because -c didn't get an argument this time)
|
||||
* this[1]="fruit" (argument to -b)
|
||||
*/
|
||||
|
||||
// What you can put in a get_opt string:
|
||||
// Any otherwise unused character (all letters, unprefixed numbers) specify
|
||||
// an option that sets a flag. The bit value is the same as the binary digit
|
||||
// if you string the option characters together in order.
|
||||
// So in "abcdefgh" a = 128, h = 1
|
||||
//
|
||||
// Suffixes specify that this option takes an argument (stored in GLOBALS):
|
||||
// Note that pointer and long are always the same size, even on 64 bit.
|
||||
// : string argument, keep most recent if more than one
|
||||
// * string argument, appended to a struct arg_list linked list.
|
||||
// # signed long argument
|
||||
// <LOW - die if less than LOW
|
||||
// >HIGH - die if greater than HIGH
|
||||
// =DEFAULT - value if not specified
|
||||
// - signed long argument defaulting to negative (say + for positive)
|
||||
// . double precision floating point argument (with CFG_TOYBOX_FLOAT)
|
||||
// Chop this option out with USE_TOYBOX_FLOAT() in option string
|
||||
// Same <LOW>HIGH=DEFAULT as #
|
||||
// @ occurrence counter (which is a long)
|
||||
// % time offset in milliseconds with optional s/m/h/d suffix
|
||||
// (longopt)
|
||||
// | this is required. If more than one marked, only one required.
|
||||
// ; long option's argument is optional (can only be supplied with --opt=)
|
||||
// ^ Stop parsing after encountering this argument
|
||||
// " " (space char) the "plus an argument" must be separate
|
||||
// I.E. "-j 3" not "-j3". So "kill -stop" != "kill -s top"
|
||||
//
|
||||
// At the beginning of the get_opt string (before any options):
|
||||
// ^ stop at first nonoption argument
|
||||
// <0 die if less than # leftover arguments (default 0)
|
||||
// >9 die if > # leftover arguments (default MAX_INT)
|
||||
// ? Allow unknown arguments (pass them through to command).
|
||||
// & first arg has imaginary dash (ala tar/ps/ar) which sets FLAGS_NODASH
|
||||
//
|
||||
// At the end: [groups] of previously seen options
|
||||
// - Only one in group (switch off) [-abc] means -ab=-b, -ba=-a, -abc=-c
|
||||
// + Synonyms (switch on all) [+abc] means -ab=-abc, -c=-abc
|
||||
// ! More than one in group is error [!abc] means -ab calls error_exit()
|
||||
// primarily useful if you can switch things back off again.
|
||||
//
|
||||
// You may use octal escapes with the high bit (127) set to use a control
|
||||
// character as an option flag. For example, \300 would be the option -@
|
||||
|
||||
// Notes from getopt man page
|
||||
// - and -- cannot be arguments.
|
||||
// -- force end of arguments
|
||||
// - is a synonym for stdin in file arguments
|
||||
// -abcd means -a -b -c -d (but if -b takes an argument, then it's -a -b cd)
|
||||
|
||||
// Linked list of all known options (option string parsed into this).
|
||||
// Hangs off getoptflagstate, freed at end of option parsing.
|
||||
struct opts {
|
||||
struct opts *next;
|
||||
long *arg; // Pointer into union "this" to store arguments at.
|
||||
int c; // Argument character to match
|
||||
int flags; // |=1, ^=2, " "=4, ;=8
|
||||
unsigned long long dex[3]; // bits to disable/enable/exclude in toys.optflags
|
||||
char type; // Type of arguments to store union "this"
|
||||
union {
|
||||
long l;
|
||||
FLOAT f;
|
||||
} val[3]; // low, high, default - range of allowed values
|
||||
};
|
||||
|
||||
// linked list of long options. (Hangs off getoptflagstate, free at end of
|
||||
// option parsing, details about flag to set and global slot to fill out
|
||||
// stored in related short option struct, but if opt->c = -1 the long option
|
||||
// is "bare" (has no corresponding short option).
|
||||
struct longopts {
|
||||
struct longopts *next;
|
||||
struct opts *opt;
|
||||
char *str;
|
||||
int len;
|
||||
};
|
||||
|
||||
// State during argument parsing.
|
||||
struct getoptflagstate
|
||||
{
|
||||
int argc, minargs, maxargs;
|
||||
char *arg;
|
||||
struct opts *opts;
|
||||
struct longopts *longopts;
|
||||
int noerror, nodash_now, stopearly;
|
||||
unsigned excludes, requires;
|
||||
};
|
||||
|
||||
// Use getoptflagstate to parse one command line option from argv
|
||||
static int gotflag(struct getoptflagstate *gof, struct opts *opt)
|
||||
{
|
||||
int type;
|
||||
|
||||
// Did we recognize this option?
|
||||
if (!opt) {
|
||||
if (gof->noerror) return 1;
|
||||
help_exit("Unknown option '%s'", gof->arg);
|
||||
}
|
||||
|
||||
// Might enabling this switch off something else?
|
||||
if (toys.optflags & opt->dex[0]) {
|
||||
struct opts *clr;
|
||||
unsigned long long i = 1;
|
||||
|
||||
// Forget saved argument for flag we switch back off
|
||||
for (clr=gof->opts, i=1; clr; clr = clr->next, i<<=1)
|
||||
if (clr->arg && (i & toys.optflags & opt->dex[0])) *clr->arg = 0;
|
||||
toys.optflags &= ~opt->dex[0];
|
||||
}
|
||||
|
||||
// Set flags
|
||||
toys.optflags |= opt->dex[1];
|
||||
gof->excludes |= opt->dex[2];
|
||||
if (opt->flags&2) gof->stopearly=2;
|
||||
|
||||
if (toys.optflags & gof->excludes) {
|
||||
struct opts *bad;
|
||||
unsigned i = 1;
|
||||
|
||||
for (bad=gof->opts, i=1; bad ;bad = bad->next, i<<=1) {
|
||||
if (opt == bad || !(i & toys.optflags)) continue;
|
||||
if (toys.optflags & bad->dex[2]) break;
|
||||
}
|
||||
if (bad) help_exit("No '%c' with '%c'", opt->c, bad->c);
|
||||
}
|
||||
|
||||
// Does this option take an argument?
|
||||
if (!gof->arg) {
|
||||
if (opt->flags & 8) return 0;
|
||||
gof->arg = "";
|
||||
} else gof->arg++;
|
||||
type = opt->type;
|
||||
|
||||
if (type == '@') ++*(opt->arg);
|
||||
else if (type) {
|
||||
char *arg = gof->arg;
|
||||
|
||||
// Handle "-xblah" and "-x blah", but also a third case: "abxc blah"
|
||||
// to make "tar xCjfv blah1 blah2 thingy" work like
|
||||
// "tar -x -C blah1 -j -f blah2 -v thingy"
|
||||
|
||||
if (gof->nodash_now || (!arg[0] && !(opt->flags & 8)))
|
||||
arg = toys.argv[++gof->argc];
|
||||
if (!arg) {
|
||||
char *s = "Missing argument to ";
|
||||
struct longopts *lo;
|
||||
|
||||
if (opt->c != -1) help_exit("%s-%c", s, opt->c);
|
||||
|
||||
for (lo = gof->longopts; lo->opt != opt; lo = lo->next);
|
||||
help_exit("%s--%.*s", s, lo->len, lo->str);
|
||||
}
|
||||
|
||||
if (type == ':') *(opt->arg) = (long)arg;
|
||||
else if (type == '*') {
|
||||
struct arg_list **list;
|
||||
|
||||
list = (struct arg_list **)opt->arg;
|
||||
while (*list) list=&((*list)->next);
|
||||
*list = xzalloc(sizeof(struct arg_list));
|
||||
(*list)->arg = arg;
|
||||
} else if (type == '#' || type == '-') {
|
||||
long l = atolx(arg);
|
||||
if (type == '-' && !ispunct(*arg)) l*=-1;
|
||||
if (l < opt->val[0].l) help_exit("-%c < %ld", opt->c, opt->val[0].l);
|
||||
if (l > opt->val[1].l) help_exit("-%c > %ld", opt->c, opt->val[1].l);
|
||||
|
||||
*(opt->arg) = l;
|
||||
} else if (CFG_TOYBOX_FLOAT && type == '.') {
|
||||
FLOAT *f = (FLOAT *)(opt->arg);
|
||||
|
||||
*f = strtod(arg, &arg);
|
||||
if (opt->val[0].l != LONG_MIN && *f < opt->val[0].f)
|
||||
help_exit("-%c < %lf", opt->c, (double)opt->val[0].f);
|
||||
if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f)
|
||||
help_exit("-%c > %lf", opt->c, (double)opt->val[1].f);
|
||||
} else if (type=='%') *(opt->arg) = xparsemillitime(arg);
|
||||
|
||||
if (!gof->nodash_now) gof->arg = "";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse this command's options string into struct getoptflagstate, which
|
||||
// includes a struct opts linked list in reverse order (I.E. right-to-left)
|
||||
void parse_optflaglist(struct getoptflagstate *gof)
|
||||
{
|
||||
char *options = toys.which->options;
|
||||
long *nextarg = (long *)&this;
|
||||
struct opts *new = 0;
|
||||
int idx;
|
||||
|
||||
// Parse option format string
|
||||
memset(gof, 0, sizeof(struct getoptflagstate));
|
||||
gof->maxargs = INT_MAX;
|
||||
if (!options) return;
|
||||
|
||||
// Parse leading special behavior indicators
|
||||
for (;;) {
|
||||
if (*options == '^') gof->stopearly++;
|
||||
else if (*options == '<') gof->minargs=*(++options)-'0';
|
||||
else if (*options == '>') gof->maxargs=*(++options)-'0';
|
||||
else if (*options == '?') gof->noerror++;
|
||||
else if (*options == '&') gof->nodash_now = 1;
|
||||
else break;
|
||||
options++;
|
||||
}
|
||||
|
||||
// Parse option string into a linked list of options with attributes.
|
||||
|
||||
if (!*options) gof->stopearly++;
|
||||
while (*options) {
|
||||
char *temp;
|
||||
|
||||
// Option groups come after all options are defined
|
||||
if (*options == '[') break;
|
||||
|
||||
// Allocate a new list entry when necessary
|
||||
if (!new) {
|
||||
new = xzalloc(sizeof(struct opts));
|
||||
new->next = gof->opts;
|
||||
gof->opts = new;
|
||||
new->val[0].l = LONG_MIN;
|
||||
new->val[1].l = LONG_MAX;
|
||||
}
|
||||
// Each option must start with "(" or an option character. (Bare
|
||||
// longopts only come at the start of the string.)
|
||||
if (*options == '(' && new->c != -1) {
|
||||
char *end;
|
||||
struct longopts *lo;
|
||||
|
||||
// Find the end of the longopt
|
||||
for (end = ++options; *end && *end != ')'; end++);
|
||||
if (CFG_TOYBOX_DEBUG && !*end) error_exit("(longopt) didn't end");
|
||||
|
||||
// init a new struct longopts
|
||||
lo = xmalloc(sizeof(struct longopts));
|
||||
lo->next = gof->longopts;
|
||||
lo->opt = new;
|
||||
lo->str = options;
|
||||
lo->len = end-options;
|
||||
gof->longopts = lo;
|
||||
options = ++end;
|
||||
|
||||
// Mark this struct opt as used, even when no short opt.
|
||||
if (!new->c) new->c = -1;
|
||||
|
||||
continue;
|
||||
|
||||
// If this is the start of a new option that wasn't a longopt,
|
||||
|
||||
} else if (strchr(":*#@.-%", *options)) {
|
||||
if (CFG_TOYBOX_DEBUG && new->type)
|
||||
error_exit("multiple types %c:%c%c", new->c, new->type, *options);
|
||||
new->type = *options;
|
||||
} else if (-1 != (idx = stridx("|^ ;", *options))) new->flags |= 1<<idx;
|
||||
// bounds checking
|
||||
else if (-1 != (idx = stridx("<>=", *options))) {
|
||||
if (new->type == '#' || new->type == '%') {
|
||||
long l = strtol(++options, &temp, 10);
|
||||
if (temp != options) new->val[idx].l = l;
|
||||
} else if (CFG_TOYBOX_FLOAT && new->type == '.') {
|
||||
FLOAT f = strtod(++options, &temp);
|
||||
if (temp != options) new->val[idx].f = f;
|
||||
} else error_exit("<>= only after .#%%");
|
||||
options = --temp;
|
||||
|
||||
// At this point, we've hit the end of the previous option. The
|
||||
// current character is the start of a new option. If we've already
|
||||
// assigned an option to this struct, loop to allocate a new one.
|
||||
// (It'll get back here afterwards and fall through to next else.)
|
||||
} else if (new->c) {
|
||||
new = 0;
|
||||
continue;
|
||||
|
||||
// Claim this option, loop to see what's after it.
|
||||
} else new->c = 127&*options;
|
||||
|
||||
options++;
|
||||
}
|
||||
|
||||
// Initialize enable/disable/exclude masks and pointers to store arguments.
|
||||
// (This goes right to left so we need the whole list before we can start.)
|
||||
idx = 0;
|
||||
for (new = gof->opts; new; new = new->next) {
|
||||
unsigned long long u = 1L<<idx++;
|
||||
|
||||
if (new->c == 1) new->c = 0;
|
||||
new->dex[1] = u;
|
||||
if (new->flags & 1) gof->requires |= u;
|
||||
if (new->type) {
|
||||
new->arg = (void *)nextarg;
|
||||
*(nextarg++) = new->val[2].l;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse trailing group indicators
|
||||
while (*options) {
|
||||
unsigned bits = 0;
|
||||
|
||||
if (CFG_TOYBOX_DEBUG && *options != '[') error_exit("trailing %s", options);
|
||||
|
||||
idx = stridx("-+!", *++options);
|
||||
if (CFG_TOYBOX_DEBUG && idx == -1) error_exit("[ needs +-!");
|
||||
if (CFG_TOYBOX_DEBUG && (options[1] == ']' || !options[1]))
|
||||
error_exit("empty []");
|
||||
|
||||
// Don't advance past ] but do process it once in loop.
|
||||
while (*options++ != ']') {
|
||||
struct opts *opt;
|
||||
int i;
|
||||
|
||||
if (CFG_TOYBOX_DEBUG && !*options) error_exit("[ without ]");
|
||||
// Find this option flag (in previously parsed struct opt)
|
||||
for (i=0, opt = gof->opts; ; i++, opt = opt->next) {
|
||||
if (*options == ']') {
|
||||
if (!opt) break;
|
||||
if (bits&(1<<i)) opt->dex[idx] |= bits&~(1<<i);
|
||||
} else {
|
||||
if (*options==1) break;
|
||||
if (CFG_TOYBOX_DEBUG && !opt)
|
||||
error_exit("[] unknown target %c", *options);
|
||||
if (opt->c == *options) {
|
||||
bits |= 1<<i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill out toys.optflags, toys.optargs, and this[] from toys.argv
|
||||
|
||||
void get_optflags(void)
|
||||
{
|
||||
struct getoptflagstate gof;
|
||||
struct opts *catch;
|
||||
unsigned long long saveflags;
|
||||
char *letters[]={"s",""};
|
||||
|
||||
// Option parsing is a two stage process: parse the option string into
|
||||
// a struct opts list, then use that list to process argv[];
|
||||
|
||||
toys.exitval = toys.which->flags >> 24;
|
||||
|
||||
// Allocate memory for optargs
|
||||
saveflags = 0;
|
||||
while (toys.argv[saveflags++]);
|
||||
toys.optargs = xzalloc(sizeof(char *)*saveflags);
|
||||
|
||||
parse_optflaglist(&gof);
|
||||
|
||||
if (toys.argv[1] && toys.argv[1][0] == '-') gof.nodash_now = 0;
|
||||
|
||||
// Iterate through command line arguments, skipping argv[0]
|
||||
for (gof.argc=1; toys.argv[gof.argc]; gof.argc++) {
|
||||
gof.arg = toys.argv[gof.argc];
|
||||
catch = NULL;
|
||||
|
||||
// Parse this argument
|
||||
if (gof.stopearly>1) goto notflag;
|
||||
|
||||
if (gof.argc>1 || *gof.arg=='-') gof.nodash_now = 0;
|
||||
|
||||
// Various things with dashes
|
||||
if (*gof.arg == '-') {
|
||||
|
||||
// Handle -
|
||||
if (!gof.arg[1]) goto notflag;
|
||||
gof.arg++;
|
||||
if (*gof.arg=='-') {
|
||||
struct longopts *lo;
|
||||
|
||||
gof.arg++;
|
||||
// Handle --
|
||||
if (!*gof.arg) {
|
||||
gof.stopearly += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// do we match a known --longopt?
|
||||
for (lo = gof.longopts; lo; lo = lo->next) {
|
||||
if (!strncmp(gof.arg, lo->str, lo->len)) {
|
||||
if (!gof.arg[lo->len]) gof.arg = 0;
|
||||
else if (gof.arg[lo->len] == '=' && lo->opt->type)
|
||||
gof.arg += lo->len;
|
||||
else continue;
|
||||
// It's a match.
|
||||
catch = lo->opt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should we handle this --longopt as a non-option argument?
|
||||
if (!lo && gof.noerror) {
|
||||
gof.arg -= 2;
|
||||
goto notflag;
|
||||
}
|
||||
|
||||
// Long option parsed, handle option.
|
||||
gotflag(&gof, catch);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle things that don't start with a dash.
|
||||
} else {
|
||||
if (gof.nodash_now) toys.optflags |= FLAGS_NODASH;
|
||||
else goto notflag;
|
||||
}
|
||||
|
||||
// At this point, we have the args part of -args. Loop through
|
||||
// each entry (could be -abc meaning -a -b -c)
|
||||
saveflags = toys.optflags;
|
||||
while (*gof.arg) {
|
||||
|
||||
// Identify next option char.
|
||||
for (catch = gof.opts; catch; catch = catch->next)
|
||||
if (*gof.arg == catch->c)
|
||||
if (!((catch->flags&4) && gof.arg[1])) break;
|
||||
|
||||
// Handle option char (advancing past what was used)
|
||||
if (gotflag(&gof, catch) ) {
|
||||
toys.optflags = saveflags;
|
||||
gof.arg = toys.argv[gof.argc];
|
||||
goto notflag;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
// Not a flag, save value in toys.optargs[]
|
||||
notflag:
|
||||
if (gof.stopearly) gof.stopearly++;
|
||||
toys.optargs[toys.optc++] = toys.argv[gof.argc];
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (toys.optc<gof.minargs)
|
||||
help_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
|
||||
gof.minargs, letters[!(gof.minargs-1)]);
|
||||
if (toys.optc>gof.maxargs)
|
||||
help_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]);
|
||||
if (gof.requires && !(gof.requires & toys.optflags)) {
|
||||
struct opts *req;
|
||||
char needs[32], *s = needs;
|
||||
|
||||
for (req = gof.opts; req; req = req->next)
|
||||
if (req->flags & 1) *(s++) = req->c;
|
||||
*s = 0;
|
||||
|
||||
help_exit("Needs %s-%s", s[1] ? "one of " : "", needs);
|
||||
}
|
||||
|
||||
toys.exitval = 0;
|
||||
|
||||
if (CFG_TOYBOX_FREE) {
|
||||
llist_traverse(gof.opts, free);
|
||||
llist_traverse(gof.longopts, free);
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/* commas.c - Deal with comma separated lists
|
||||
*
|
||||
* Copyright 2018 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// Traverse arg_list of csv, calling callback on each value
|
||||
void comma_args(struct arg_list *al, void *data, char *err,
|
||||
char *(*callback)(void *data, char *str, int len))
|
||||
{
|
||||
char *next, *arg;
|
||||
int len;
|
||||
|
||||
if (CFG_TOYBOX_DEBUG && !err) err = "INTERNAL";
|
||||
|
||||
while (al) {
|
||||
arg = al->arg;
|
||||
while ((next = comma_iterate(&arg, &len)))
|
||||
if ((next = callback(data, next, len)))
|
||||
error_exit("%s '%s'\n%*c", err, al->arg,
|
||||
(int)(5+strlen(toys.which->name)+strlen(err)+next-al->arg), '^');
|
||||
al = al->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Realloc *old with oldstring,newstring
|
||||
|
||||
void comma_collate(char **old, char *new)
|
||||
{
|
||||
char *temp, *atold = *old;
|
||||
|
||||
// Only add a comma if old string didn't end with one
|
||||
if (atold && *atold) {
|
||||
char *comma = ",";
|
||||
|
||||
if (atold[strlen(atold)-1] == ',') comma = "";
|
||||
temp = xmprintf("%s%s%s", atold, comma, new);
|
||||
} else temp = xstrdup(new);
|
||||
free (atold);
|
||||
*old = temp;
|
||||
}
|
||||
|
||||
// iterate through strings in a comma separated list.
|
||||
// returns start of next entry or NULL if none
|
||||
// sets *len to length of entry (not including comma)
|
||||
// advances *list to start of next entry
|
||||
char *comma_iterate(char **list, int *len)
|
||||
{
|
||||
char *start = *list, *end;
|
||||
|
||||
if (!*list || !**list) return 0;
|
||||
|
||||
if (!(end = strchr(*list, ','))) {
|
||||
*len = strlen(*list);
|
||||
*list = 0;
|
||||
} else *list += (*len = end-start)+1;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
// Check all instances of opt and "no"opt in optlist, return true if opt
|
||||
// found and last instance wasn't no. If clean, remove each instance from list.
|
||||
int comma_scan(char *optlist, char *opt, int clean)
|
||||
{
|
||||
int optlen = strlen(opt), len, no, got = 0;
|
||||
|
||||
if (optlist) for (;;) {
|
||||
char *s = comma_iterate(&optlist, &len);
|
||||
|
||||
if (!s) break;
|
||||
no = 2*(*s == 'n' && s[1] == 'o');
|
||||
if (optlen == len-no && !strncmp(opt, s+no, optlen)) {
|
||||
got = !no;
|
||||
if (clean) {
|
||||
if (optlist) memmove(s, optlist, strlen(optlist)+1);
|
||||
else *s = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return got;
|
||||
}
|
||||
|
||||
// return true if all scanlist options enabled in optlist
|
||||
int comma_scanall(char *optlist, char *scanlist)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
while (scanlist && *scanlist) {
|
||||
char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i);
|
||||
|
||||
i = comma_scan(optlist, s, 0);
|
||||
free(s);
|
||||
if (!i) break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Returns true and removes `opt` from `optlist` if present, false otherwise.
|
||||
// Doesn't have the magic "no" behavior of comma_scan.
|
||||
int comma_remove(char *optlist, char *opt)
|
||||
{
|
||||
int optlen = strlen(opt), len, got = 0;
|
||||
|
||||
if (optlist) for (;;) {
|
||||
char *s = comma_iterate(&optlist, &len);
|
||||
|
||||
if (!s) break;
|
||||
if (optlen == len && !strncmp(opt, s, optlen)) {
|
||||
got = 1;
|
||||
if (optlist) memmove(s, optlist, strlen(optlist)+1);
|
||||
else *s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return got;
|
||||
}
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
/* deflate.c - deflate/inflate code for gzip and friends
|
||||
*
|
||||
* Copyright 2014 Rob Landley <rob@landley.net>
|
||||
*
|
||||
* See RFCs 1950 (zlib), 1951 (deflate), and 1952 (gzip)
|
||||
* LSB 4.1 has gzip, gunzip, and zcat
|
||||
*
|
||||
* TODO: zip -d DIR -x LIST -list -quiet -no overwrite -overwrite -p to stdout
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
struct deflate {
|
||||
// Huffman codes: base offset and extra bits tables (length and distance)
|
||||
char lenbits[29], distbits[30];
|
||||
unsigned short lenbase[29], distbase[30];
|
||||
void *fixdisthuff, *fixlithuff;
|
||||
|
||||
// CRC
|
||||
void (*crcfunc)(struct deflate *dd, char *data, int len);
|
||||
unsigned crctable[256], crc;
|
||||
|
||||
|
||||
// Tables only used for deflation
|
||||
unsigned short *hashhead, *hashchain;
|
||||
|
||||
// Compressed data buffer (extra space malloced at end)
|
||||
unsigned pos, len;
|
||||
int infd, outfd;
|
||||
char data[];
|
||||
};
|
||||
|
||||
// little endian bit buffer
|
||||
struct bitbuf {
|
||||
int fd, bitpos, len, max;
|
||||
char buf[];
|
||||
};
|
||||
|
||||
// malloc a struct bitbuf
|
||||
struct bitbuf *bitbuf_init(int fd, int size)
|
||||
{
|
||||
struct bitbuf *bb = xzalloc(sizeof(struct bitbuf)+size);
|
||||
|
||||
bb->max = size;
|
||||
bb->fd = fd;
|
||||
|
||||
return bb;
|
||||
}
|
||||
|
||||
// Advance bitpos without the overhead of recording bits
|
||||
// Loads more data when input buffer empty
|
||||
void bitbuf_skip(struct bitbuf *bb, int bits)
|
||||
{
|
||||
int pos = bb->bitpos + bits, len = bb->len << 3;
|
||||
|
||||
while (pos >= len) {
|
||||
pos -= len;
|
||||
len = (bb->len = read(bb->fd, bb->buf, bb->max)) << 3;
|
||||
if (bb->len < 1) perror_exit("inflate EOF");
|
||||
}
|
||||
bb->bitpos = pos;
|
||||
}
|
||||
|
||||
// Optimized single bit inlined version
|
||||
static inline int bitbuf_bit(struct bitbuf *bb)
|
||||
{
|
||||
int bufpos = bb->bitpos>>3;
|
||||
|
||||
if (bufpos == bb->len) {
|
||||
bitbuf_skip(bb, 0);
|
||||
bufpos = 0;
|
||||
}
|
||||
|
||||
return (bb->buf[bufpos]>>(bb->bitpos++&7))&1;
|
||||
}
|
||||
|
||||
// Fetch the next X bits from the bitbuf, little endian
|
||||
unsigned bitbuf_get(struct bitbuf *bb, int bits)
|
||||
{
|
||||
int result = 0, offset = 0;
|
||||
|
||||
while (bits) {
|
||||
int click = bb->bitpos >> 3, blow, blen;
|
||||
|
||||
// Load more data if buffer empty
|
||||
if (click == bb->len) bitbuf_skip(bb, click = 0);
|
||||
|
||||
// grab bits from next byte
|
||||
blow = bb->bitpos & 7;
|
||||
blen = 8-blow;
|
||||
if (blen > bits) blen = bits;
|
||||
result |= ((bb->buf[click] >> blow) & ((1<<blen)-1)) << offset;
|
||||
offset += blen;
|
||||
bits -= blen;
|
||||
bb->bitpos += blen;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bitbuf_flush(struct bitbuf *bb)
|
||||
{
|
||||
if (!bb->bitpos) return;
|
||||
|
||||
xwrite(bb->fd, bb->buf, (bb->bitpos+7)>>3);
|
||||
memset(bb->buf, 0, bb->max);
|
||||
bb->bitpos = 0;
|
||||
}
|
||||
|
||||
void bitbuf_put(struct bitbuf *bb, int data, int len)
|
||||
{
|
||||
while (len) {
|
||||
int click = bb->bitpos >> 3, blow, blen;
|
||||
|
||||
// Flush buffer if necessary
|
||||
if (click == bb->max) {
|
||||
bitbuf_flush(bb);
|
||||
click = 0;
|
||||
}
|
||||
blow = bb->bitpos & 7;
|
||||
blen = 8-blow;
|
||||
if (blen > len) blen = len;
|
||||
bb->buf[click] |= data << blow;
|
||||
bb->bitpos += blen;
|
||||
data >>= blen;
|
||||
len -= blen;
|
||||
}
|
||||
}
|
||||
|
||||
static void output_byte(struct deflate *dd, char sym)
|
||||
{
|
||||
int pos = dd->pos++ & 32767;
|
||||
|
||||
dd->data[pos] = sym;
|
||||
|
||||
if (pos == 32767) {
|
||||
xwrite(dd->outfd, dd->data, 32768);
|
||||
if (dd->crcfunc) dd->crcfunc(dd, dd->data, 32768);
|
||||
}
|
||||
}
|
||||
|
||||
// Huffman coding uses bits to traverse a binary tree to a leaf node,
|
||||
// By placing frequently occurring symbols at shorter paths, frequently
|
||||
// used symbols may be represented in fewer bits than uncommon symbols.
|
||||
// (length[0] isn't used but code's clearer if it's there.)
|
||||
|
||||
struct huff {
|
||||
unsigned short length[16]; // How many symbols have this bit length?
|
||||
unsigned short symbol[288]; // sorted by bit length, then ascending order
|
||||
};
|
||||
|
||||
// Create simple huffman tree from array of bit lengths.
|
||||
|
||||
// The symbols in the huffman trees are sorted (first by bit length
|
||||
// of the code to reach them, then by symbol number). This means that given
|
||||
// the bit length of each symbol, we can construct a unique tree.
|
||||
static void len2huff(struct huff *huff, char bitlen[], int len)
|
||||
{
|
||||
int offset[16];
|
||||
int i;
|
||||
|
||||
// Count number of codes at each bit length
|
||||
memset(huff, 0, sizeof(struct huff));
|
||||
for (i = 0; i<len; i++) huff->length[bitlen[i]]++;
|
||||
|
||||
// Sort symbols by bit length, then symbol. Get list of starting positions
|
||||
// for each group, then write each symbol to next position within its group.
|
||||
*huff->length = *offset = 0;
|
||||
for (i = 1; i<16; i++) offset[i] = offset[i-1] + huff->length[i-1];
|
||||
for (i = 0; i<len; i++) if (bitlen[i]) huff->symbol[offset[bitlen[i]]++] = i;
|
||||
}
|
||||
|
||||
// Fetch and decode next huffman coded symbol from bitbuf.
|
||||
// This takes advantage of the sorting to navigate the tree as an array:
|
||||
// each time we fetch a bit we have all the codes at that bit level in
|
||||
// order with no gaps.
|
||||
static unsigned huff_and_puff(struct bitbuf *bb, struct huff *huff)
|
||||
{
|
||||
unsigned short *length = huff->length;
|
||||
int start = 0, offset = 0;
|
||||
|
||||
// Traverse through the bit lengths until our code is in this range
|
||||
for (;;) {
|
||||
offset = (offset << 1) | bitbuf_bit(bb);
|
||||
start += *++length;
|
||||
if ((offset -= *length) < 0) break;
|
||||
if ((length - huff->length) & 16) error_exit("bad symbol");
|
||||
}
|
||||
|
||||
return huff->symbol[start + offset];
|
||||
}
|
||||
|
||||
// Decompress deflated data from bitbuf to dd->outfd.
|
||||
static void inflate(struct deflate *dd, struct bitbuf *bb)
|
||||
{
|
||||
dd->crc = ~0;
|
||||
// repeat until spanked
|
||||
for (;;) {
|
||||
int final, type;
|
||||
|
||||
final = bitbuf_get(bb, 1);
|
||||
type = bitbuf_get(bb, 2);
|
||||
|
||||
if (type == 3) error_exit("bad type");
|
||||
|
||||
// Uncompressed block?
|
||||
if (!type) {
|
||||
int len, nlen;
|
||||
|
||||
// Align to byte, read length
|
||||
bitbuf_skip(bb, (8-bb->bitpos)&7);
|
||||
len = bitbuf_get(bb, 16);
|
||||
nlen = bitbuf_get(bb, 16);
|
||||
if (len != (0xffff & ~nlen)) error_exit("bad len");
|
||||
|
||||
// Dump literal output data
|
||||
while (len) {
|
||||
int pos = bb->bitpos >> 3, bblen = bb->len - pos;
|
||||
char *p = bb->buf+pos;
|
||||
|
||||
// dump bytes until done or end of current bitbuf contents
|
||||
if (bblen > len) bblen = len;
|
||||
pos = bblen;
|
||||
while (pos--) output_byte(dd, *(p++));
|
||||
bitbuf_skip(bb, bblen << 3);
|
||||
len -= bblen;
|
||||
}
|
||||
|
||||
// Compressed block
|
||||
} else {
|
||||
struct huff *disthuff, *lithuff;
|
||||
|
||||
// Dynamic huffman codes?
|
||||
if (type == 2) {
|
||||
struct huff *h2 = ((struct huff *)libbuf)+1;
|
||||
int i, litlen, distlen, hufflen;
|
||||
char *hufflen_order = "\x10\x11\x12\0\x08\x07\x09\x06\x0a\x05\x0b"
|
||||
"\x04\x0c\x03\x0d\x02\x0e\x01\x0f", *bits;
|
||||
|
||||
// The huffman trees are stored as a series of bit lengths
|
||||
litlen = bitbuf_get(bb, 5)+257; // max 288
|
||||
distlen = bitbuf_get(bb, 5)+1; // max 32
|
||||
hufflen = bitbuf_get(bb, 4)+4; // max 19
|
||||
|
||||
// The literal and distance codes are themselves compressed, in
|
||||
// a complicated way: an array of bit lengths (hufflen many
|
||||
// entries, each 3 bits) is used to fill out an array of 19 entries
|
||||
// in a magic order, leaving the rest 0. Then make a tree out of it:
|
||||
memset(bits = libbuf+1, 0, 19);
|
||||
for (i=0; i<hufflen; i++) bits[hufflen_order[i]] = bitbuf_get(bb, 3);
|
||||
len2huff(h2, bits, 19);
|
||||
|
||||
// Use that tree to read in the literal and distance bit lengths
|
||||
for (i = 0; i < litlen + distlen;) {
|
||||
int sym = huff_and_puff(bb, h2);
|
||||
|
||||
// 0-15 are literals, 16 = repeat previous code 3-6 times,
|
||||
// 17 = 3-10 zeroes (3 bit), 18 = 11-138 zeroes (7 bit)
|
||||
if (sym < 16) bits[i++] = sym;
|
||||
else {
|
||||
int len = sym & 2;
|
||||
|
||||
len = bitbuf_get(bb, sym-14+len+(len>>1)) + 3 + (len<<2);
|
||||
memset(bits+i, bits[i-1] * !(sym&3), len);
|
||||
i += len;
|
||||
}
|
||||
}
|
||||
if (i > litlen+distlen) error_exit("bad tree");
|
||||
|
||||
len2huff(lithuff = h2, bits, litlen);
|
||||
len2huff(disthuff = ((struct huff *)libbuf)+2, bits+litlen, distlen);
|
||||
|
||||
// Static huffman codes
|
||||
} else {
|
||||
lithuff = dd->fixlithuff;
|
||||
disthuff = dd->fixdisthuff;
|
||||
}
|
||||
|
||||
// Use huffman tables to decode block of compressed symbols
|
||||
for (;;) {
|
||||
int sym = huff_and_puff(bb, lithuff);
|
||||
|
||||
// Literal?
|
||||
if (sym < 256) output_byte(dd, sym);
|
||||
|
||||
// Copy range?
|
||||
else if (sym > 256) {
|
||||
int len, dist;
|
||||
|
||||
sym -= 257;
|
||||
len = dd->lenbase[sym] + bitbuf_get(bb, dd->lenbits[sym]);
|
||||
sym = huff_and_puff(bb, disthuff);
|
||||
dist = dd->distbase[sym] + bitbuf_get(bb, dd->distbits[sym]);
|
||||
sym = dd->pos & 32767;
|
||||
|
||||
while (len--) output_byte(dd, dd->data[(dd->pos-dist) & 32767]);
|
||||
|
||||
// End of block
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
|
||||
// Was that the last block?
|
||||
if (final) break;
|
||||
}
|
||||
|
||||
if (dd->pos & 32767) {
|
||||
xwrite(dd->outfd, dd->data, dd->pos&32767);
|
||||
if (dd->crcfunc) dd->crcfunc(dd, dd->data, dd->pos&32767);
|
||||
}
|
||||
}
|
||||
|
||||
// Deflate from dd->infd to bitbuf
|
||||
// For deflate, dd->len = input read, dd->pos = input consumed
|
||||
static void deflate(struct deflate *dd, struct bitbuf *bb)
|
||||
{
|
||||
char *data = dd->data;
|
||||
int len, final = 0;
|
||||
|
||||
dd->crc = ~0;
|
||||
|
||||
while (!final) {
|
||||
// Read next half-window of data if we haven't hit EOF yet.
|
||||
len = readall(dd->infd, data+(dd->len&32768), 32768);
|
||||
if (len < 0) perror_exit("read"); // todo: add filename
|
||||
if (len != 32768) final++;
|
||||
if (dd->crcfunc) dd->crcfunc(dd, data+(dd->len&32768), len);
|
||||
// dd->len += len; crcfunc advances len TODO
|
||||
|
||||
// store block as literal
|
||||
bitbuf_put(bb, final, 1);
|
||||
bitbuf_put(bb, 0, 1);
|
||||
|
||||
bitbuf_put(bb, 0, (8-bb->bitpos)&7);
|
||||
bitbuf_put(bb, len, 16);
|
||||
bitbuf_put(bb, 0xffff & ~len, 16);
|
||||
|
||||
// repeat until spanked
|
||||
while (dd->pos != dd->len) {
|
||||
unsigned pos = dd->pos&65535;
|
||||
|
||||
bitbuf_put(bb, data[pos], 8);
|
||||
|
||||
// need to refill buffer?
|
||||
if (!(32767 & ++dd->pos) && !final) break;
|
||||
}
|
||||
}
|
||||
bitbuf_flush(bb);
|
||||
}
|
||||
|
||||
// Allocate memory for deflate/inflate.
|
||||
static struct deflate *init_deflate(int compress)
|
||||
{
|
||||
int i, n = 1;
|
||||
struct deflate *dd = xmalloc(sizeof(struct deflate)+32768*(compress ? 4 : 1));
|
||||
|
||||
memset(dd, 0, sizeof(struct deflate));
|
||||
// decompress needs 32k history, compress adds 64k hashhead and 32k hashchain
|
||||
if (compress) {
|
||||
dd->hashhead = (unsigned short *)(dd->data+65536);
|
||||
dd->hashchain = (unsigned short *)(dd->data+65536+32768);
|
||||
}
|
||||
|
||||
// Calculate lenbits, lenbase, distbits, distbase
|
||||
*dd->lenbase = 3;
|
||||
for (i = 0; i<sizeof(dd->lenbits)-1; i++) {
|
||||
if (i>4) {
|
||||
if (!(i&3)) {
|
||||
dd->lenbits[i]++;
|
||||
n <<= 1;
|
||||
}
|
||||
if (i == 27) n--;
|
||||
else dd->lenbits[i+1] = dd->lenbits[i];
|
||||
}
|
||||
dd->lenbase[i+1] = n + dd->lenbase[i];
|
||||
}
|
||||
n = 0;
|
||||
for (i = 0; i<sizeof(dd->distbits); i++) {
|
||||
dd->distbase[i] = 1<<n;
|
||||
if (i) dd->distbase[i] += dd->distbase[i-1];
|
||||
if (i>3 && !(i&1)) n++;
|
||||
dd->distbits[i] = n;
|
||||
}
|
||||
|
||||
// TODO layout and lifetime of this?
|
||||
// Init fixed huffman tables
|
||||
for (i=0; i<288; i++) libbuf[i] = 8 + (i>143) - ((i>255)<<1) + (i>279);
|
||||
len2huff(dd->fixlithuff = ((struct huff *)libbuf)+3, libbuf, 288);
|
||||
memset(libbuf, 5, 30);
|
||||
len2huff(dd->fixdisthuff = ((struct huff *)libbuf)+4, libbuf, 30);
|
||||
|
||||
return dd;
|
||||
}
|
||||
|
||||
// Return true/false whether we consumed a gzip header.
|
||||
static int is_gzip(struct bitbuf *bb)
|
||||
{
|
||||
int flags;
|
||||
|
||||
// Confirm signature
|
||||
if (bitbuf_get(bb, 24) != 0x088b1f || (flags = bitbuf_get(bb, 8)) > 31)
|
||||
return 0;
|
||||
bitbuf_skip(bb, 6*8);
|
||||
|
||||
// Skip extra, name, comment, header CRC fields
|
||||
if (flags & 4) bitbuf_skip(bb, 16);
|
||||
if (flags & 8) while (bitbuf_get(bb, 8));
|
||||
if (flags & 16) while (bitbuf_get(bb, 8));
|
||||
if (flags & 2) bitbuf_skip(bb, 16);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void gzip_crc(struct deflate *dd, char *data, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned crc, *crc_table = dd->crctable;
|
||||
|
||||
crc = dd->crc;
|
||||
for (i=0; i<len; i++) crc = crc_table[(crc^data[i])&0xff] ^ (crc>>8);
|
||||
dd->crc = crc;
|
||||
dd->len += len;
|
||||
}
|
||||
|
||||
long long gzip_fd(int infd, int outfd)
|
||||
{
|
||||
struct bitbuf *bb = bitbuf_init(outfd, 4096);
|
||||
struct deflate *dd = init_deflate(1);
|
||||
long long rc;
|
||||
|
||||
// Header from RFC 1952 section 2.2:
|
||||
// 2 ID bytes (1F, 8b), gzip method byte (8=deflate), FLAG byte (none),
|
||||
// 4 byte MTIME (zeroed), Extra Flags (2=maximum compression),
|
||||
// Operating System (FF=unknown)
|
||||
|
||||
dd->infd = infd;
|
||||
xwrite(bb->fd, "\x1f\x8b\x08\0\0\0\0\0\x02\xff", 10);
|
||||
|
||||
// Little endian crc table
|
||||
crc_init(dd->crctable, 1);
|
||||
dd->crcfunc = gzip_crc;
|
||||
|
||||
deflate(dd, bb);
|
||||
|
||||
// tail: crc32, len32
|
||||
|
||||
bitbuf_put(bb, 0, (8-bb->bitpos)&7);
|
||||
bitbuf_put(bb, ~dd->crc, 32);
|
||||
bitbuf_put(bb, dd->len, 32);
|
||||
rc = dd->len;
|
||||
|
||||
bitbuf_flush(bb);
|
||||
free(bb);
|
||||
free(dd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
long long gunzip_fd(int infd, int outfd)
|
||||
{
|
||||
struct bitbuf *bb = bitbuf_init(infd, 4096);
|
||||
struct deflate *dd = init_deflate(0);
|
||||
long long rc;
|
||||
|
||||
if (!is_gzip(bb)) error_exit("not gzip");
|
||||
dd->outfd = outfd;
|
||||
|
||||
// Little endian crc table
|
||||
crc_init(dd->crctable, 1);
|
||||
dd->crcfunc = gzip_crc;
|
||||
|
||||
inflate(dd, bb);
|
||||
|
||||
// tail: crc32, len32
|
||||
|
||||
bitbuf_skip(bb, (8-bb->bitpos)&7);
|
||||
if (~dd->crc != bitbuf_get(bb, 32) || dd->len != bitbuf_get(bb, 32))
|
||||
error_exit("bad crc");
|
||||
|
||||
rc = dd->len;
|
||||
free(bb);
|
||||
free(dd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
/* dirtree.c - Functions for dealing with directory trees.
|
||||
*
|
||||
* Copyright 2007 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
int isdotdot(char *name)
|
||||
{
|
||||
if (name[0]=='.' && (!name[1] || (name[1]=='.' && !name[2]))) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Default callback, filters out "." and ".." except at top level.
|
||||
|
||||
int dirtree_notdotdot(struct dirtree *catch)
|
||||
{
|
||||
// Should we skip "." and ".."?
|
||||
return (!catch->parent||!isdotdot(catch->name))
|
||||
*(DIRTREE_SAVE|DIRTREE_RECURSE);
|
||||
}
|
||||
|
||||
// Create a dirtree node from a path, with stat and symlink info.
|
||||
// (This doesn't open directory filehandles yet so as not to exhaust the
|
||||
// filehandle space on large trees, dirtree_handle_callback() does that.)
|
||||
|
||||
struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, int flags)
|
||||
{
|
||||
struct dirtree *dt = 0;
|
||||
struct stat st;
|
||||
int len = 0, linklen = 0, statless = 0;
|
||||
|
||||
if (name) {
|
||||
// open code this because haven't got node to call dirtree_parentfd() on yet
|
||||
int fd = parent ? parent->dirfd : AT_FDCWD;
|
||||
|
||||
if (fstatat(fd, name, &st,AT_SYMLINK_NOFOLLOW*!(flags&DIRTREE_SYMFOLLOW))) {
|
||||
if (flags&DIRTREE_STATLESS) statless++;
|
||||
else goto error;
|
||||
}
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
if (0>(linklen = readlinkat(fd, name, libbuf, 4095))) goto error;
|
||||
libbuf[linklen++]=0;
|
||||
}
|
||||
len = strlen(name);
|
||||
}
|
||||
|
||||
// Allocate/populate return structure
|
||||
dt = xmalloc((len = sizeof(struct dirtree)+len+1)+linklen);
|
||||
memset(dt, 0, statless ? offsetof(struct dirtree, again)
|
||||
: offsetof(struct dirtree, st));
|
||||
dt->parent = parent;
|
||||
dt->again = statless ? 2 : 0;
|
||||
if (!statless) memcpy(&dt->st, &st, sizeof(struct stat));
|
||||
strcpy(dt->name, name ? name : "");
|
||||
if (linklen) dt->symlink = memcpy(len+(char *)dt, libbuf, linklen);
|
||||
|
||||
return dt;
|
||||
|
||||
error:
|
||||
if (!(flags&DIRTREE_SHUTUP) && !isdotdot(name)) {
|
||||
char *path = parent ? dirtree_path(parent, 0) : "";
|
||||
|
||||
perror_msg("%s%s%s", path, parent ? "/" : "", name);
|
||||
if (parent) free(path);
|
||||
}
|
||||
if (parent) parent->symlink = (char *)1;
|
||||
free(dt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return path to this node, assembled recursively.
|
||||
|
||||
// Initial call can pass in NULL to plen, or point to an int initialized to 0
|
||||
// to return the length of the path, or a value greater than 0 to allocate
|
||||
// extra space if you want to append your own text to the string.
|
||||
|
||||
char *dirtree_path(struct dirtree *node, int *plen)
|
||||
{
|
||||
char *path;
|
||||
int len;
|
||||
|
||||
if (!node) {
|
||||
path = xmalloc(*plen);
|
||||
*plen = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
len = (plen ? *plen : 0)+strlen(node->name)+1;
|
||||
path = dirtree_path(node->parent, &len);
|
||||
if (len && path[len-1] != '/') path[len++]='/';
|
||||
len = stpcpy(path+len, node->name) - path;
|
||||
if (plen) *plen = len;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
int dirtree_parentfd(struct dirtree *node)
|
||||
{
|
||||
return node->parent ? node->parent->dirfd : AT_FDCWD;
|
||||
}
|
||||
|
||||
// Handle callback for a node in the tree. Returns saved node(s) if
|
||||
// callback returns DIRTREE_SAVE, otherwise frees consumed nodes and
|
||||
// returns NULL. If !callback return top node unchanged.
|
||||
// If !new return DIRTREE_ABORTVAL
|
||||
|
||||
struct dirtree *dirtree_handle_callback(struct dirtree *new,
|
||||
int (*callback)(struct dirtree *node))
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (!new) return DIRTREE_ABORTVAL;
|
||||
if (!callback) return new;
|
||||
flags = callback(new);
|
||||
|
||||
if (S_ISDIR(new->st.st_mode) && (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)))
|
||||
flags = dirtree_recurse(new, callback,
|
||||
openat(dirtree_parentfd(new), new->name, O_CLOEXEC), flags);
|
||||
|
||||
// If this had children, it was callback's job to free them already.
|
||||
if (!(flags & DIRTREE_SAVE)) {
|
||||
free(new);
|
||||
new = 0;
|
||||
}
|
||||
|
||||
return (flags & DIRTREE_ABORT)==DIRTREE_ABORT ? DIRTREE_ABORTVAL : new;
|
||||
}
|
||||
|
||||
// Recursively read/process children of directory node, filtering through
|
||||
// callback(). Uses and closes supplied ->dirfd.
|
||||
|
||||
int dirtree_recurse(struct dirtree *node,
|
||||
int (*callback)(struct dirtree *node), int dirfd, int flags)
|
||||
{
|
||||
struct dirtree *new, **ddt = &(node->child);
|
||||
struct dirent *entry;
|
||||
DIR *dir;
|
||||
|
||||
node->dirfd = dirfd;
|
||||
if (node->dirfd == -1 || !(dir = fdopendir(node->dirfd))) {
|
||||
if (!(flags & DIRTREE_SHUTUP)) {
|
||||
char *path = dirtree_path(node, 0);
|
||||
perror_msg_raw(path);
|
||||
free(path);
|
||||
}
|
||||
close(node->dirfd);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// according to the fddir() man page, the filehandle in the DIR * can still
|
||||
// be externally used by things that don't lseek() it.
|
||||
|
||||
// The extra parentheses are to shut the stupid compiler up.
|
||||
while ((entry = readdir(dir))) {
|
||||
if ((flags&DIRTREE_PROC) && !isdigit(*entry->d_name)) continue;
|
||||
if (!(new = dirtree_add_node(node, entry->d_name, flags))) continue;
|
||||
if (!new->st.st_blksize && !new->st.st_mode)
|
||||
new->st.st_mode = entry->d_type<<12;
|
||||
new = dirtree_handle_callback(new, callback);
|
||||
if (new == DIRTREE_ABORTVAL) break;
|
||||
if (new) {
|
||||
*ddt = new;
|
||||
ddt = &((*ddt)->next);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DIRTREE_COMEAGAIN) {
|
||||
node->again |= 1;
|
||||
flags = callback(node);
|
||||
}
|
||||
|
||||
// This closes filehandle as well, so note it
|
||||
closedir(dir);
|
||||
node->dirfd = -1;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Create dirtree from path, using callback to filter nodes. If !callback
|
||||
// return just the top node. Use dirtree_notdotdot callback to allocate a
|
||||
// tree of struct dirtree nodes and return pointer to root node for later
|
||||
// processing.
|
||||
// Returns DIRTREE_ABORTVAL if path didn't exist (use DIRTREE_SHUTUP to handle
|
||||
// error message yourself).
|
||||
|
||||
struct dirtree *dirtree_flagread(char *path, int flags,
|
||||
int (*callback)(struct dirtree *node))
|
||||
{
|
||||
return dirtree_handle_callback(dirtree_add_node(0, path, flags), callback);
|
||||
}
|
||||
|
||||
// Common case
|
||||
struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node))
|
||||
{
|
||||
return dirtree_flagread(path, 0, callback);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Can't trust libc not to leak enviornment variable memory, so...
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// In libc, populated by start code,used by getenv() and exec() and friends.
|
||||
extern char **environ;
|
||||
|
||||
// Returns the number of bytes taken by the environment variables. For use
|
||||
// when calculating the maximum bytes of environment+argument data that can
|
||||
// be passed to exec for find(1) and xargs(1).
|
||||
long environ_bytes()
|
||||
{
|
||||
long bytes = sizeof(char *);
|
||||
char **ev;
|
||||
|
||||
for (ev = environ; *ev; ev++) bytes += sizeof(char *) + strlen(*ev) + 1;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// This will clear the inherited environment if called first thing.
|
||||
// Use this instead of envc so we keep track of what needs to be freed.
|
||||
void xclearenv(void)
|
||||
{
|
||||
toys.envc = 0;
|
||||
*environ = 0;
|
||||
}
|
||||
|
||||
// Frees entries we set earlier. Use with libc getenv but not setenv/putenv.
|
||||
// if name has an equals and !val, act like putenv (name=val must be malloced!)
|
||||
// if !val unset name. (Name with = and val is an error)
|
||||
void xsetenv(char *name, char *val)
|
||||
{
|
||||
unsigned i, len, envc;
|
||||
char *new;
|
||||
|
||||
// If we haven't snapshot initial environment state yet, do so now.
|
||||
if (!toys.envc) {
|
||||
// envc is size +1 so even if env empty it's nonzero after initialization
|
||||
while (environ[toys.envc++]);
|
||||
memcpy(new = xmalloc(((toys.envc|0xff)+1)*sizeof(char *)),
|
||||
environ, toys.envc*sizeof(char *));
|
||||
environ = (void *)new;
|
||||
}
|
||||
|
||||
new = strchr(name, '=');
|
||||
if (new) {
|
||||
len = new-name;
|
||||
if (val) error_exit("xsetenv %s to %s", name, val);
|
||||
new = name;
|
||||
} else {
|
||||
len = strlen(name);
|
||||
if (val) new = xmprintf("%s=%s", name, val);
|
||||
}
|
||||
|
||||
envc = toys.envc-1; // compensate for size +1 above
|
||||
for (i = 0; environ[i]; i++) {
|
||||
// Drop old entry, freeing as appropriate. Assumes no duplicates.
|
||||
if (!memcmp(name, environ[i], len) && environ[i][len]=='=') {
|
||||
if (i>=envc) free(environ[i]);
|
||||
else {
|
||||
// move old entries down, add at end of old data
|
||||
toys.envc = envc--;
|
||||
for (; new ? i<envc : !!environ[i]; i++) environ[i] = environ[i+1];
|
||||
i = envc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!new) return;
|
||||
|
||||
// resize and null terminate if expanding
|
||||
if (!environ[i]) {
|
||||
len = i+1;
|
||||
if (!(len&255)) environ = xrealloc(environ, len*sizeof(char *));
|
||||
environ[len] = 0;
|
||||
}
|
||||
environ[i] = new;
|
||||
}
|
||||
|
||||
void xunsetenv(char *name)
|
||||
{
|
||||
if (strchr(name, '=')) error_exit("xunsetenv %s name has =", name);
|
||||
xsetenv(name, 0);
|
||||
}
|
||||
|
||||
// reset environment for a user, optionally clearing most of it
|
||||
void reset_env(struct passwd *p, int clear)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (clear) {
|
||||
char *s, *stuff[] = {"TERM", "DISPLAY", "COLORTERM", "XAUTHORITY"};
|
||||
|
||||
for (i=0; i<ARRAY_LEN(stuff); i++)
|
||||
stuff[i] = (s = getenv(stuff[i])) ? xmprintf("%s=%s", stuff[i], s) : 0;
|
||||
xclearenv();
|
||||
for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) xsetenv(stuff[i], 0);
|
||||
if (chdir(p->pw_dir)) {
|
||||
perror_msg("chdir %s", p->pw_dir);
|
||||
xchdir("/");
|
||||
}
|
||||
} else {
|
||||
char **ev1, **ev2;
|
||||
|
||||
// remove LD_*, IFS, ENV, and BASH_ENV from environment
|
||||
for (ev1 = ev2 = environ;;) {
|
||||
while (*ev2 && (strstart(ev2, "LD_") || strstart(ev2, "IFS=") ||
|
||||
strstart(ev2, "ENV=") || strstart(ev2, "BASH_ENV="))) ev2++;
|
||||
if (!(*ev1++ = *ev2++)) break;
|
||||
}
|
||||
}
|
||||
|
||||
setenv("PATH", _PATH_DEFPATH, 1);
|
||||
setenv("HOME", p->pw_dir, 1);
|
||||
setenv("SHELL", p->pw_shell, 1);
|
||||
setenv("USER", p->pw_name, 1);
|
||||
setenv("LOGNAME", p->pw_name, 1);
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Function to display help text
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
#include "generated/help.h"
|
||||
|
||||
#undef NEWTOY
|
||||
#undef OLDTOY
|
||||
#define NEWTOY(name,opt,flags) HELP_##name "\0"
|
||||
#if CFG_TOYBOX
|
||||
#define OLDTOY(name,oldname,flags) "\xff" #oldname "\0"
|
||||
#else
|
||||
#define OLDTOY(name, oldname, flags) HELP_##oldname "\0"
|
||||
#endif
|
||||
static char *help_data =
|
||||
#include "generated/newtoys.h"
|
||||
;
|
||||
|
||||
void show_help(FILE *out)
|
||||
{
|
||||
int i = toys.which-toy_list;
|
||||
char *s;
|
||||
|
||||
if (CFG_TOYBOX_HELP) {
|
||||
for (;;) {
|
||||
s = help_data;
|
||||
while (i--) s += strlen(s) + 1;
|
||||
// If it's an alias, restart search for real name
|
||||
if (*s != 255) break;
|
||||
i = toy_find(++s)-toy_list;
|
||||
}
|
||||
|
||||
fprintf(out, "%s\n", s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
/* lib.h - header file for lib directory
|
||||
*
|
||||
* Copyright 2006 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
struct ptr_len {
|
||||
void *ptr;
|
||||
long len;
|
||||
};
|
||||
|
||||
struct str_len {
|
||||
char *str;
|
||||
long len;
|
||||
};
|
||||
|
||||
// llist.c
|
||||
|
||||
// All these list types can be handled by the same code because first element
|
||||
// is always next pointer, so next = (mytype *)&struct. (The payloads are
|
||||
// named differently to catch using the wrong type early.)
|
||||
|
||||
struct string_list {
|
||||
struct string_list *next;
|
||||
char str[0];
|
||||
};
|
||||
|
||||
struct arg_list {
|
||||
struct arg_list *next;
|
||||
char *arg;
|
||||
};
|
||||
|
||||
struct double_list {
|
||||
struct double_list *next, *prev;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct num_cache {
|
||||
struct num_cache *next;
|
||||
long long num;
|
||||
char data[];
|
||||
};
|
||||
|
||||
void llist_free_arg(void *node);
|
||||
void llist_free_double(void *node);
|
||||
void llist_traverse(void *list, void (*using)(void *node));
|
||||
void *llist_pop(void *list); // actually void **list
|
||||
void *dlist_pop(void *list); // actually struct double_list **list
|
||||
void *dlist_lpop(void *list); // also struct double_list **list
|
||||
void dlist_add_nomalloc(struct double_list **list, struct double_list *new);
|
||||
struct double_list *dlist_add(struct double_list **list, char *data);
|
||||
void *dlist_terminate(void *list);
|
||||
struct num_cache *get_num_cache(struct num_cache *cache, long long num);
|
||||
struct num_cache *add_num_cache(struct num_cache **cache, long long num,
|
||||
void *data, int len);
|
||||
|
||||
// args.c
|
||||
#define FLAGS_NODASH (1LL<<63)
|
||||
void get_optflags(void);
|
||||
|
||||
// dirtree.c
|
||||
|
||||
// Values returnable from callback function (bitfield, or them together)
|
||||
// Default with no callback is 0
|
||||
|
||||
// Add this node to the tree
|
||||
#define DIRTREE_SAVE 1
|
||||
// Recurse into children
|
||||
#define DIRTREE_RECURSE 2
|
||||
// Call again after handling all children of this directory
|
||||
// (Ignored for non-directories, sets linklen = -1 before second call.)
|
||||
#define DIRTREE_COMEAGAIN 4
|
||||
// Follow symlinks to directories
|
||||
#define DIRTREE_SYMFOLLOW 8
|
||||
// Don't warn about failure to stat
|
||||
#define DIRTREE_SHUTUP 16
|
||||
// Breadth first traversal, conserves filehandles at the expense of memory
|
||||
#define DIRTREE_BREADTH 32
|
||||
// skip non-numeric entries
|
||||
#define DIRTREE_PROC 64
|
||||
// Return files we can't stat
|
||||
#define DIRTREE_STATLESS 128
|
||||
// Don't look at any more files in this directory.
|
||||
#define DIRTREE_ABORT 256
|
||||
|
||||
#define DIRTREE_ABORTVAL ((struct dirtree *)1)
|
||||
|
||||
struct dirtree {
|
||||
struct dirtree *next, *parent, *child;
|
||||
long extra; // place for user to store their stuff (can be pointer)
|
||||
char *symlink;
|
||||
int dirfd;
|
||||
struct stat st;
|
||||
char again;
|
||||
char name[];
|
||||
};
|
||||
|
||||
int isdotdot(char *name);
|
||||
struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int flags);
|
||||
char *dirtree_path(struct dirtree *node, int *plen);
|
||||
int dirtree_notdotdot(struct dirtree *catch);
|
||||
int dirtree_parentfd(struct dirtree *node);
|
||||
int dirtree_recurse(struct dirtree *node, int (*callback)(struct dirtree *node),
|
||||
int dirfd, int symfollow);
|
||||
struct dirtree *dirtree_flagread(char *path, int flags,
|
||||
int (*callback)(struct dirtree *node));
|
||||
struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node));
|
||||
|
||||
// help.c
|
||||
|
||||
void show_help(FILE *out);
|
||||
|
||||
// Tell xopen and friends to print warnings but return -1 as necessary
|
||||
// The largest O_BLAH flag so far is arch/alpha's O_PATH at 0x800000 so
|
||||
// plenty of headroom.
|
||||
#define WARN_ONLY (1<<31)
|
||||
|
||||
// xwrap.c
|
||||
void xstrncpy(char *dest, char *src, size_t size);
|
||||
void xstrncat(char *dest, char *src, size_t size);
|
||||
void _xexit(void) __attribute__((__noreturn__));
|
||||
void xexit(void) __attribute__((__noreturn__));
|
||||
void *xmmap(void *addr, size_t length, int prot, int flags, int fd, off_t off);
|
||||
void *xmalloc(size_t size);
|
||||
void *xzalloc(size_t size);
|
||||
void *xrealloc(void *ptr, size_t size);
|
||||
char *xstrndup(char *s, size_t n);
|
||||
char *xstrdup(char *s);
|
||||
void *xmemdup(void *s, long len);
|
||||
char *xmprintf(char *format, ...) printf_format;
|
||||
void xprintf(char *format, ...) printf_format;
|
||||
void xputsl(char *s, int len);
|
||||
void xputsn(char *s);
|
||||
void xputs(char *s);
|
||||
void xputc(char c);
|
||||
void xflush(int flush);
|
||||
void xexec(char **argv);
|
||||
pid_t xpopen_both(char **argv, int *pipes);
|
||||
int xwaitpid(pid_t pid);
|
||||
int xpclose_both(pid_t pid, int *pipes);
|
||||
pid_t xpopen(char **argv, int *pipe, int isstdout);
|
||||
pid_t xpclose(pid_t pid, int pipe);
|
||||
int xrun(char **argv);
|
||||
int xpspawn(char **argv, int*pipes);
|
||||
void xaccess(char *path, int flags);
|
||||
void xunlink(char *path);
|
||||
void xrename(char *from, char *to);
|
||||
int xtempfile(char *name, char **tempname);
|
||||
int xcreate(char *path, int flags, int mode);
|
||||
int xopen(char *path, int flags);
|
||||
int xcreate_stdio(char *path, int flags, int mode);
|
||||
int xopen_stdio(char *path, int flags);
|
||||
int openro(char *path, int flags);
|
||||
int xopenro(char *path);
|
||||
void xpipe(int *pp);
|
||||
void xclose(int fd);
|
||||
int xdup(int fd);
|
||||
int notstdio(int fd);
|
||||
FILE *xfdopen(int fd, char *mode);
|
||||
FILE *xfopen(char *path, char *mode);
|
||||
size_t xread(int fd, void *buf, size_t len);
|
||||
void xreadall(int fd, void *buf, size_t len);
|
||||
void xwrite(int fd, void *buf, size_t len);
|
||||
off_t xlseek(int fd, off_t offset, int whence);
|
||||
char *xreadfile(char *name, char *buf, off_t len);
|
||||
int xioctl(int fd, int request, void *data);
|
||||
char *xgetcwd(void);
|
||||
void xstat(char *path, struct stat *st);
|
||||
char *xabspath(char *path, int exact);
|
||||
void xchdir(char *path);
|
||||
void xchroot(char *path);
|
||||
struct passwd *xgetpwuid(uid_t uid);
|
||||
struct group *xgetgrgid(gid_t gid);
|
||||
struct passwd *xgetpwnam(char *name);
|
||||
struct group *xgetgrnam(char *name);
|
||||
unsigned xgetuid(char *name);
|
||||
unsigned xgetgid(char *name);
|
||||
void xsetuser(struct passwd *pwd);
|
||||
char *xreadlink(char *name);
|
||||
double xstrtod(char *s);
|
||||
long xparsetime(char *arg, long units, long *fraction);
|
||||
long long xparsemillitime(char *arg);
|
||||
void xpidfile(char *name);
|
||||
void xregcomp(regex_t *preg, char *rexec, int cflags);
|
||||
char *xtzset(char *new);
|
||||
void xsignal_flags(int signal, void *handler, int flags);
|
||||
void xsignal(int signal, void *handler);
|
||||
time_t xvali_date(struct tm *tm, char *str);
|
||||
void xparsedate(char *str, time_t *t, unsigned *nano, int endian);
|
||||
char *xgetline(FILE *fp, int *len);
|
||||
|
||||
// lib.c
|
||||
void verror_msg(char *msg, int err, va_list va);
|
||||
void error_msg(char *msg, ...) printf_format;
|
||||
void perror_msg(char *msg, ...) printf_format;
|
||||
void error_exit(char *msg, ...) printf_format __attribute__((__noreturn__));
|
||||
void perror_exit(char *msg, ...) printf_format __attribute__((__noreturn__));
|
||||
void help_exit(char *msg, ...) printf_format __attribute__((__noreturn__));
|
||||
void error_msg_raw(char *msg);
|
||||
void perror_msg_raw(char *msg);
|
||||
void error_exit_raw(char *msg);
|
||||
void perror_exit_raw(char *msg);
|
||||
ssize_t readall(int fd, void *buf, size_t len);
|
||||
ssize_t writeall(int fd, void *buf, size_t len);
|
||||
off_t lskip(int fd, off_t offset);
|
||||
#define MKPATHAT_MKLAST 1
|
||||
#define MKPATHAT_MAKE 2
|
||||
#define MKPATHAT_VERBOSE 4
|
||||
int mkpathat(int atfd, char *dir, mode_t lastmode, int flags);
|
||||
int mkpath(char *dir);
|
||||
struct string_list **splitpath(char *path, struct string_list **list);
|
||||
char *readfileat(int dirfd, char *name, char *buf, off_t *len);
|
||||
char *readfile(char *name, char *buf, off_t len);
|
||||
void msleep(long milliseconds);
|
||||
void nanomove(struct timespec *ts, long long offset);
|
||||
long long nanodiff(struct timespec *old, struct timespec *new);
|
||||
int highest_bit(unsigned long l);
|
||||
int64_t peek_le(void *ptr, unsigned size);
|
||||
int64_t peek_be(void *ptr, unsigned size);
|
||||
int64_t peek(void *ptr, unsigned size);
|
||||
void poke_le(void *ptr, long long val, unsigned size);
|
||||
void poke_be(void *ptr, long long val, unsigned size);
|
||||
void poke(void *ptr, long long val, unsigned size);
|
||||
struct string_list *find_in_path(char *path, char *filename);
|
||||
long long estrtol(char *str, char **end, int base);
|
||||
long long xstrtol(char *str, char **end, int base);
|
||||
long long atolx(char *c);
|
||||
long long atolx_range(char *numstr, long long low, long long high);
|
||||
int stridx(char *haystack, char needle);
|
||||
int utf8towc(wchar_t *wc, char *str, unsigned len);
|
||||
char *strlower(char *s);
|
||||
char *strafter(char *haystack, char *needle);
|
||||
char *chomp(char *s);
|
||||
int unescape(char c);
|
||||
char *strend(char *str, char *suffix);
|
||||
int strstart(char **a, char *b);
|
||||
int strcasestart(char **a, char *b);
|
||||
off_t fdlength(int fd);
|
||||
void loopfiles_rw(char **argv, int flags, int permissions,
|
||||
void (*function)(int fd, char *name));
|
||||
void loopfiles(char **argv, void (*function)(int fd, char *name));
|
||||
void loopfiles_lines(char **argv, void (*function)(char **pline, long len));
|
||||
long long sendfile_len(int in, int out, long long len, long long *consumed);
|
||||
long long xsendfile_len(int in, int out, long long len);
|
||||
void xsendfile_pad(int in, int out, long long len);
|
||||
long long xsendfile(int in, int out);
|
||||
int wfchmodat(int rc, char *name, mode_t mode);
|
||||
int copy_tempfile(int fdin, char *name, char **tempname);
|
||||
void delete_tempfile(int fdin, int fdout, char **tempname);
|
||||
void replace_tempfile(int fdin, int fdout, char **tempname);
|
||||
void crc_init(unsigned int *crc_table, int little_endian);
|
||||
void base64_init(char *p);
|
||||
int yesno(int def);
|
||||
int fyesno(FILE *fp, int def);
|
||||
int qstrcmp(const void *a, const void *b);
|
||||
void create_uuid(char *uuid);
|
||||
char *show_uuid(char *uuid);
|
||||
char *next_printf(char *s, char **start);
|
||||
int dev_minor(int dev);
|
||||
int dev_major(int dev);
|
||||
int dev_makedev(int major, int minor);
|
||||
struct passwd *bufgetpwuid(uid_t uid);
|
||||
struct group *bufgetgrgid(gid_t gid);
|
||||
int readlinkat0(int dirfd, char *path, char *buf, int len);
|
||||
int readlink0(char *path, char *buf, int len);
|
||||
int regexec0(regex_t *preg, char *string, long len, int nmatch,
|
||||
regmatch_t pmatch[], int eflags);
|
||||
char *getusername(uid_t uid);
|
||||
char *getgroupname(gid_t gid);
|
||||
void do_lines(int fd, char delim, void (*call)(char **pline, long len));
|
||||
long long millitime(void);
|
||||
char *format_iso_time(char *buf, size_t len, struct timespec *ts);
|
||||
void reset_env(struct passwd *p, int clear);
|
||||
void loggit(int priority, char *format, ...);
|
||||
unsigned tar_cksum(void *data);
|
||||
int is_tar_header(void *pkt);
|
||||
|
||||
#define HR_SPACE 1 // Space between number and units
|
||||
#define HR_B 2 // Use "B" for single byte units
|
||||
#define HR_1000 4 // Use decimal instead of binary units
|
||||
int human_readable_long(char *buf, unsigned long long num, int dgt, int style);
|
||||
int human_readable(char *buf, unsigned long long num, int style);
|
||||
|
||||
// env.c
|
||||
|
||||
long environ_bytes();
|
||||
void xsetenv(char *name, char *val);
|
||||
void xunsetenv(char *name);
|
||||
void xclearenv(void);
|
||||
|
||||
// linestack.c
|
||||
|
||||
struct linestack {
|
||||
long len, max;
|
||||
struct ptr_len idx[];
|
||||
};
|
||||
|
||||
void linestack_addstack(struct linestack **lls, struct linestack *throw,
|
||||
long pos);
|
||||
void linestack_insert(struct linestack **lls, long pos, char *line, long len);
|
||||
void linestack_append(struct linestack **lls, char *line);
|
||||
struct linestack *linestack_load(char *name);
|
||||
int crunch_escape(FILE *out, int cols, int wc);
|
||||
int crunch_rev_escape(FILE *out, int cols, int wc);
|
||||
int crunch_str(char **str, int width, FILE *out, char *escmore,
|
||||
int (*escout)(FILE *out, int cols, int wc));
|
||||
int draw_str(char *start, int width);
|
||||
int utf8len(char *str);
|
||||
int utf8skip(char *str, int width);
|
||||
int draw_trim_esc(char *str, int padto, int width, char *escmore,
|
||||
int (*escout)(FILE *out, int cols,int wc));
|
||||
int draw_trim(char *str, int padto, int width);
|
||||
|
||||
// tty.c
|
||||
int tty_fd(void);
|
||||
int terminal_size(unsigned *xx, unsigned *yy);
|
||||
int terminal_probesize(unsigned *xx, unsigned *yy);
|
||||
#define KEY_UP 0
|
||||
#define KEY_DOWN 1
|
||||
#define KEY_RIGHT 2
|
||||
#define KEY_LEFT 3
|
||||
#define KEY_PGUP 4
|
||||
#define KEY_PGDN 5
|
||||
#define KEY_HOME 6
|
||||
#define KEY_END 7
|
||||
#define KEY_INSERT 8
|
||||
#define KEY_DELETE 9
|
||||
#define KEY_FN 10 // F1 = KEY_FN+1, F2 = KEY_FN+2, ...
|
||||
#define KEY_SHIFT (1<<16)
|
||||
#define KEY_CTRL (1<<17)
|
||||
#define KEY_ALT (1<<18)
|
||||
int scan_key(char *scratch, int timeout_ms);
|
||||
int scan_key_getsize(char *scratch, int timeout_ms, unsigned *xx, unsigned *yy);
|
||||
int set_terminal(int fd, int raw, int speed, struct termios *old);
|
||||
void xset_terminal(int fd, int raw, int speed, struct termios *old);
|
||||
void tty_esc(char *s);
|
||||
void tty_jump(int x, int y);
|
||||
void tty_reset(void);
|
||||
void tty_sigreset(int i);
|
||||
void start_redraw(unsigned *width, unsigned *height);
|
||||
|
||||
// net.c
|
||||
|
||||
union socksaddr {
|
||||
struct sockaddr s;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
};
|
||||
|
||||
int xsocket(int domain, int type, int protocol);
|
||||
void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len);
|
||||
struct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype,
|
||||
int protocol, int flags);
|
||||
void xbind(int fd, const struct sockaddr *sa, socklen_t len);
|
||||
void xconnect(int fd, const struct sockaddr *sa, socklen_t len);
|
||||
int xconnectany(struct addrinfo *ai);
|
||||
int xbindany(struct addrinfo *ai);
|
||||
int xpoll(struct pollfd *fds, int nfds, int timeout);
|
||||
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout);
|
||||
char *ntop(struct sockaddr *sa);
|
||||
void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest);
|
||||
int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout);
|
||||
|
||||
// password.c
|
||||
int get_salt(char *salt, char * algo);
|
||||
|
||||
// commas.c
|
||||
void comma_args(struct arg_list *al, void *data, char *err,
|
||||
char *(*callback)(void *data, char *str, int len));
|
||||
void comma_collate(char **old, char *new);
|
||||
char *comma_iterate(char **list, int *len);
|
||||
int comma_scan(char *optlist, char *opt, int clean);
|
||||
int comma_scanall(char *optlist, char *scanlist);
|
||||
int comma_remove(char *optlist, char *opt);
|
||||
|
||||
// deflate.c
|
||||
|
||||
long long gzip_fd(int infd, int outfd);
|
||||
long long gunzip_fd(int infd, int outfd);
|
||||
|
||||
// getmountlist.c
|
||||
struct mtab_list {
|
||||
struct mtab_list *next, *prev;
|
||||
struct stat stat;
|
||||
struct statvfs statvfs;
|
||||
char *dir;
|
||||
char *device;
|
||||
char *opts;
|
||||
char type[0];
|
||||
};
|
||||
|
||||
int mountlist_istype(struct mtab_list *ml, char *typelist);
|
||||
struct mtab_list *xgetmountlist(char *path);
|
||||
|
||||
// signal
|
||||
|
||||
void generic_signal(int signal);
|
||||
void exit_signal(int signal);
|
||||
void sigatexit(void *handler);
|
||||
void list_signals();
|
||||
|
||||
mode_t string_to_mode(char *mode_str, mode_t base);
|
||||
void mode_to_string(mode_t mode, char *buf);
|
||||
char *getdirname(char *name);
|
||||
char *getbasename(char *name);
|
||||
char *fileunderdir(char *file, char *dir);
|
||||
void names_to_pid(char **names, int (*callback)(pid_t pid, char *name),
|
||||
int scripts);
|
||||
|
||||
pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid);
|
||||
#define XVFORK() xvforkwrap(vfork())
|
||||
|
||||
// Wrapper to make xfuncs() return (via siglongjmp) instead of exiting.
|
||||
// Assigns true/false "did it exit" value to first argument.
|
||||
#define WOULD_EXIT(y, x) do { sigjmp_buf _noexit; \
|
||||
int _noexit_res; \
|
||||
toys.rebound = &_noexit; \
|
||||
_noexit_res = sigsetjmp(_noexit, 1); \
|
||||
if (!_noexit_res) do {x;} while(0); \
|
||||
toys.rebound = 0; \
|
||||
y = _noexit_res; \
|
||||
} while(0)
|
||||
|
||||
// Wrapper that discards true/false "did it exit" value.
|
||||
#define NOEXIT(x) WOULD_EXIT(_noexit_res, x)
|
||||
|
||||
#define minof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aa<bb ? aa : bb;})
|
||||
#define maxof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aa>bb ? aa : bb;})
|
||||
|
||||
// Functions in need of further review/cleanup
|
||||
#include "lib/pending.h"
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
#include "toys.h"
|
||||
|
||||
// The design idea here is indexing a big blob of (potentially mmaped) data
|
||||
// instead of copying the data into a zillion seperate malloc()s.
|
||||
|
||||
// A linestack is an array of struct ptr_len, with a currently used len
|
||||
// and max tracking the memory allocation. This indexes existing string data,
|
||||
// the lifetime of which is tracked externally.
|
||||
|
||||
// Insert one stack into another before position in old stack.
|
||||
// (Does not copy contents of strings, just shuffles index array contents.)
|
||||
void linestack_addstack(struct linestack **lls, struct linestack *throw,
|
||||
long pos)
|
||||
{
|
||||
struct linestack *catch = *lls;
|
||||
|
||||
if (CFG_TOYBOX_DEBUG)
|
||||
if (pos > catch->len) error_exit("linestack_addstack past end.");
|
||||
|
||||
// Make a hole, allocating more space if necessary.
|
||||
if (catch->len+throw->len >= catch->max) {
|
||||
// New size rounded up to next multiple of 64, allocate and copy start.
|
||||
catch->max = ((catch->len+throw->len)|63)+1;
|
||||
*lls = xmalloc(sizeof(struct linestack)+catch->max*sizeof(struct ptr_len));
|
||||
memcpy(*lls, catch, sizeof(struct linestack)+pos*sizeof(struct ptr_len));
|
||||
}
|
||||
|
||||
// Copy end (into new allocation if necessary)
|
||||
if (pos != catch->len)
|
||||
memmove((*lls)->idx+pos+throw->len, catch->idx+pos,
|
||||
(catch->len-pos)*sizeof(struct ptr_len));
|
||||
|
||||
// Cleanup if we had to realloc.
|
||||
if (catch != *lls) {
|
||||
free(catch);
|
||||
catch = *lls;
|
||||
}
|
||||
|
||||
// Copy new chunk we made space for
|
||||
memcpy(catch->idx+pos, throw->idx, throw->len*sizeof(struct ptr_len));
|
||||
catch->len += throw->len;
|
||||
}
|
||||
|
||||
// Insert one line/len into a linestack at pos
|
||||
void linestack_insert(struct linestack **lls, long pos, char *line, long len)
|
||||
{
|
||||
// alloca() was in 32V and Turbo C for DOS, but isn't in posix or c99.
|
||||
// This allocates enough memory for the linestack to have one ptr_len.
|
||||
// (Even if a compiler adds gratuitous padidng that just makes it bigger.)
|
||||
struct {
|
||||
struct ptr_len pl;
|
||||
struct linestack ls;
|
||||
} ls;
|
||||
|
||||
ls.ls.len = ls.ls.max = 1;
|
||||
ls.ls.idx[0].ptr = line;
|
||||
ls.ls.idx[0].len = len;
|
||||
linestack_addstack(lls, &ls.ls, pos);
|
||||
}
|
||||
|
||||
void linestack_append(struct linestack **lls, char *line)
|
||||
{
|
||||
linestack_insert(lls, (*lls)->len, line, strlen(line));
|
||||
}
|
||||
|
||||
struct linestack *linestack_load(char *name)
|
||||
{
|
||||
FILE *fp = fopen(name, "r");
|
||||
struct linestack *ls;
|
||||
|
||||
if (!fp) return 0;
|
||||
|
||||
ls = xzalloc(sizeof(struct linestack));
|
||||
|
||||
for (;;) {
|
||||
char *line = 0;
|
||||
ssize_t len;
|
||||
|
||||
if ((len = getline(&line, (void *)&len, fp))<1) break;
|
||||
if (line[len-1]=='\n') len--;
|
||||
linestack_insert(&ls, ls->len, line, len);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
// Show width many columns, negative means from right edge, out=0 just measure
|
||||
// if escout, send it unprintable chars, otherwise pass through raw data.
|
||||
// Returns width in columns, moves *str to end of data consumed.
|
||||
int crunch_str(char **str, int width, FILE *out, char *escmore,
|
||||
int (*escout)(FILE *out, int cols, int wc))
|
||||
{
|
||||
int columns = 0, col, bytes;
|
||||
char *start, *end;
|
||||
|
||||
for (end = start = *str; *end; columns += col, end += bytes) {
|
||||
wchar_t wc;
|
||||
|
||||
if ((bytes = utf8towc(&wc, end, 4))>0 && (col = wcwidth(wc))>=0) {
|
||||
if (!escmore || wc>255 || !strchr(escmore, wc)) {
|
||||
if (width-columns<col) break;
|
||||
if (out) fwrite(end, bytes, 1, out);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes<1) {
|
||||
bytes = 1;
|
||||
wc = *end;
|
||||
}
|
||||
col = width-columns;
|
||||
if (col<1) break;
|
||||
if (escout) {
|
||||
if ((col = escout(out, col, wc))<0) break;
|
||||
} else if (out) fwrite(end, 1, bytes, out);
|
||||
}
|
||||
*str = end;
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
|
||||
// standard escapes: ^X if <32, <XX> if invalid UTF8, U+XXXX if UTF8 !iswprint()
|
||||
int crunch_escape(FILE *out, int cols, int wc)
|
||||
{
|
||||
char buf[11];
|
||||
int rc;
|
||||
|
||||
if (wc<' ') rc = sprintf(buf, "^%c", '@'+wc);
|
||||
else if (wc<256) rc = sprintf(buf, "<%02X>", wc);
|
||||
else rc = sprintf(buf, "U+%04X", wc);
|
||||
|
||||
if (rc > cols) buf[rc = cols] = 0;
|
||||
if (out) fputs(buf, out);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Display "standard" escapes in reverse video.
|
||||
int crunch_rev_escape(FILE *out, int cols, int wc)
|
||||
{
|
||||
int rc;
|
||||
|
||||
tty_esc("7m");
|
||||
rc = crunch_escape(out, cols, wc);
|
||||
tty_esc("27m");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Write width chars at start of string to strdout with standard escapes
|
||||
// Returns length in columns so caller can pad it out with spaces.
|
||||
int draw_str(char *start, int width)
|
||||
{
|
||||
return crunch_str(&start, width, stdout, 0, crunch_rev_escape);
|
||||
}
|
||||
|
||||
// Return utf8 columns
|
||||
int utf8len(char *str)
|
||||
{
|
||||
return crunch_str(&str, INT_MAX, 0, 0, crunch_rev_escape);
|
||||
}
|
||||
|
||||
// Return bytes used by (up to) this many columns
|
||||
int utf8skip(char *str, int width)
|
||||
{
|
||||
char *s = str;
|
||||
|
||||
crunch_str(&s, width, 0, 0, crunch_rev_escape);
|
||||
|
||||
return s-str;
|
||||
}
|
||||
|
||||
// Print utf8 to stdout with standard escapes, trimmed to width and padded
|
||||
// out to padto. If padto<0 left justify. Returns columns printed
|
||||
int draw_trim_esc(char *str, int padto, int width, char *escmore,
|
||||
int (*escout)(FILE *out, int cols, int wc))
|
||||
{
|
||||
int apad = abs(padto), len = utf8len(str);
|
||||
|
||||
if (padto>=0 && len>width) str += utf8skip(str, len-width);
|
||||
if (len>width) len = width;
|
||||
|
||||
// Left pad if right justified
|
||||
if (padto>0 && apad>len) printf("%*s", apad-len, "");
|
||||
crunch_str(&str, len, stdout, 0, crunch_rev_escape);
|
||||
if (padto<0 && apad>len) printf("%*s", apad-len, "");
|
||||
|
||||
return (apad > len) ? apad : len;
|
||||
}
|
||||
|
||||
// draw_trim_esc() with default escape
|
||||
int draw_trim(char *str, int padto, int width)
|
||||
{
|
||||
return draw_trim_esc(str, padto, width, 0, 0);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/* llist.c - Linked list functions
|
||||
*
|
||||
* Linked list structures have a next pointer as their first element.
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// Callback function to free data pointer of double_list or arg_list
|
||||
|
||||
void llist_free_arg(void *node)
|
||||
{
|
||||
struct arg_list *d = node;
|
||||
|
||||
free(d->arg);
|
||||
free(d);
|
||||
}
|
||||
|
||||
void llist_free_double(void *node)
|
||||
{
|
||||
struct double_list *d = node;
|
||||
|
||||
free(d->data);
|
||||
free(d);
|
||||
}
|
||||
|
||||
// Call a function (such as free()) on each element of a linked list.
|
||||
void llist_traverse(void *list, void (*using)(void *node))
|
||||
{
|
||||
void *old = list;
|
||||
|
||||
while (list) {
|
||||
void *pop = llist_pop(&list);
|
||||
using(pop);
|
||||
|
||||
// End doubly linked list too.
|
||||
if (old == list) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the first item from the list, advancing the list (which must be called
|
||||
// as &list)
|
||||
void *llist_pop(void *list)
|
||||
{
|
||||
// I'd use a void ** for the argument, and even accept the typecast in all
|
||||
// callers as documentation you need the &, except the stupid compiler
|
||||
// would then scream about type-punned pointers. Screw it.
|
||||
void **llist = (void **)list;
|
||||
void **next = (void **)*llist;
|
||||
*llist = *next;
|
||||
|
||||
return (void *)next;
|
||||
}
|
||||
|
||||
// Remove first item from &list and return it
|
||||
void *dlist_pop(void *list)
|
||||
{
|
||||
struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
|
||||
|
||||
if (!dlist) return 0;
|
||||
if (dlist->next == dlist) *pdlist = 0;
|
||||
else {
|
||||
if (dlist->next) dlist->next->prev = dlist->prev;
|
||||
if (dlist->prev) dlist->prev->next = dlist->next;
|
||||
*pdlist = dlist->next;
|
||||
}
|
||||
|
||||
return dlist;
|
||||
}
|
||||
|
||||
// remove last item from &list and return it (stack pop)
|
||||
void *dlist_lpop(void *list)
|
||||
{
|
||||
struct double_list *dl = *(struct double_list **)list;
|
||||
void *v = 0;
|
||||
|
||||
if (dl) {
|
||||
dl = dl->prev;
|
||||
v = dlist_pop(&dl);
|
||||
if (!dl) *(void **)list = 0;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
|
||||
{
|
||||
if (*list) {
|
||||
new->next = *list;
|
||||
new->prev = (*list)->prev;
|
||||
(*list)->prev->next = new;
|
||||
(*list)->prev = new;
|
||||
} else *list = new->next = new->prev = new;
|
||||
}
|
||||
|
||||
|
||||
// Add an entry to the end of a doubly linked list
|
||||
struct double_list *dlist_add(struct double_list **list, char *data)
|
||||
{
|
||||
struct double_list *new = xmalloc(sizeof(struct double_list));
|
||||
|
||||
new->data = data;
|
||||
dlist_add_nomalloc(list, new);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
// Terminate circular list for traversal in either direction. Returns end *.
|
||||
void *dlist_terminate(void *list)
|
||||
{
|
||||
struct double_list *end = list;
|
||||
|
||||
if (!list) return 0;
|
||||
|
||||
end = end->prev;
|
||||
end->next->prev = 0;
|
||||
end->next = 0;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
// Find num in cache
|
||||
struct num_cache *get_num_cache(struct num_cache *cache, long long num)
|
||||
{
|
||||
while (cache) {
|
||||
if (num==cache->num) return cache;
|
||||
cache = cache->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Uniquely add num+data to cache. Updates *cache, returns pointer to existing
|
||||
// entry if it was already there.
|
||||
struct num_cache *add_num_cache(struct num_cache **cache, long long num,
|
||||
void *data, int len)
|
||||
{
|
||||
struct num_cache *old = get_num_cache(*cache, num);
|
||||
|
||||
if (old) return old;
|
||||
|
||||
old = xzalloc(sizeof(struct num_cache)+len);
|
||||
old->next = *cache;
|
||||
old->num = num;
|
||||
memcpy(old->data, data, len);
|
||||
*cache = old;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/* lsm.h - header file for lib directory
|
||||
*
|
||||
* Copyright 2015 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#if CFG_TOYBOX_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#else
|
||||
#define is_selinux_enabled() 0
|
||||
#define setfscreatecon(...) (-1)
|
||||
#define getcon(...) (-1)
|
||||
#define getfilecon(...) (-1)
|
||||
#define lgetfilecon(...) (-1)
|
||||
#define fgetfilecon(...) (-1)
|
||||
#define setfilecon(...) (-1)
|
||||
#define lsetfilecon(...) (-1)
|
||||
#define fsetfilecon(...) (-1)
|
||||
#endif
|
||||
|
||||
#if CFG_TOYBOX_SMACK
|
||||
#include <sys/smack.h>
|
||||
#include <linux/xattr.h>
|
||||
#else
|
||||
#ifndef XATTR_NAME_SMACK
|
||||
#define XATTR_NAME_SMACK 0
|
||||
#endif
|
||||
#define smack_smackfs_path(...) (-1)
|
||||
#define smack_new_label_from_self(...) (-1)
|
||||
#define smack_new_label_from_path(...) (-1)
|
||||
#define smack_new_label_from_file(...) (-1)
|
||||
#define smack_set_label_for_self(...) (-1)
|
||||
#define smack_set_label_for_path(...) (-1)
|
||||
#define smack_set_label_for_file(...) (-1)
|
||||
#endif
|
||||
|
||||
// This turns into "return 0" when no LSM and lets code optimize out.
|
||||
static inline int lsm_enabled(void)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK) return !!smack_smackfs_path();
|
||||
else return is_selinux_enabled() == 1;
|
||||
}
|
||||
|
||||
static inline char *lsm_name(void)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK) return "Smack";
|
||||
if (CFG_TOYBOX_SELINUX) return "SELinux";
|
||||
|
||||
return "LSM";
|
||||
}
|
||||
|
||||
// Fetch this process's lsm context
|
||||
static inline char *lsm_context(void)
|
||||
{
|
||||
int ok = 0;
|
||||
char *result = 0;
|
||||
|
||||
if (CFG_TOYBOX_SMACK) ok = smack_new_label_from_self(&result) > 0;
|
||||
else ok = getcon(&result) == 0;
|
||||
|
||||
return ok ? result : strdup("?");
|
||||
}
|
||||
|
||||
// Set default label to apply to newly created stuff (NULL to clear it)
|
||||
static inline int lsm_set_create(char *context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK) return smack_set_label_for_self(context);
|
||||
else return setfscreatecon(context);
|
||||
}
|
||||
|
||||
// Label a file, following symlinks
|
||||
static inline int lsm_set_context(char *filename, char *context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 1, context);
|
||||
else return setfilecon(filename, context);
|
||||
}
|
||||
|
||||
// Label a file, don't follow symlinks
|
||||
static inline int lsm_lset_context(char *filename, char *context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_set_label_for_path(filename, XATTR_NAME_SMACK, 0, context);
|
||||
else return lsetfilecon(filename, context);
|
||||
}
|
||||
|
||||
// Label a file by filehandle
|
||||
static inline int lsm_fset_context(int file, char *context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_set_label_for_file(file, XATTR_NAME_SMACK, context);
|
||||
else return fsetfilecon(file, context);
|
||||
}
|
||||
|
||||
// returns -1 in case of error or else the length of the context */
|
||||
// context can be NULL to get the length only */
|
||||
static inline int lsm_get_context(char *filename, char **context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 1, context);
|
||||
else return getfilecon(filename, context);
|
||||
}
|
||||
|
||||
static inline int lsm_lget_context(char *filename, char **context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_new_label_from_path(filename, XATTR_NAME_SMACK, 0, context);
|
||||
else return lgetfilecon(filename, context);
|
||||
}
|
||||
|
||||
static inline int lsm_fget_context(int file, char **context)
|
||||
{
|
||||
if (CFG_TOYBOX_SMACK)
|
||||
return smack_new_label_from_file(file, XATTR_NAME_SMACK, context);
|
||||
return fgetfilecon(file, context);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "toys.h"
|
||||
|
||||
int xsocket(int domain, int type, int protocol)
|
||||
{
|
||||
int fd = socket(domain, type, protocol);
|
||||
|
||||
if (fd < 0) perror_exit("socket %x %x", type, protocol);
|
||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len)
|
||||
{
|
||||
if (-1 == setsockopt(fd, level, opt, val, len)) perror_exit("setsockopt");
|
||||
}
|
||||
|
||||
// if !host bind to all local interfaces
|
||||
struct addrinfo *xgetaddrinfo(char *host, char *port, int family, int socktype,
|
||||
int protocol, int flags)
|
||||
{
|
||||
struct addrinfo info, *ai;
|
||||
int rc;
|
||||
|
||||
memset(&info, 0, sizeof(struct addrinfo));
|
||||
info.ai_family = family;
|
||||
info.ai_socktype = socktype;
|
||||
info.ai_protocol = protocol;
|
||||
info.ai_flags = flags;
|
||||
if (!host) info.ai_flags |= AI_PASSIVE;
|
||||
|
||||
rc = getaddrinfo(host, port, &info, &ai);
|
||||
if (rc || !ai)
|
||||
error_exit("%s%s%s: %s", host ? host : "*", port ? ":" : "",
|
||||
port ? port : "", rc ? gai_strerror(rc) : "not found");
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
static int xconnbind(struct addrinfo *ai_arg, int dobind)
|
||||
{
|
||||
struct addrinfo *ai;
|
||||
int fd = -1, one = 1;
|
||||
|
||||
// Try all the returned addresses. Report errors if last entry can't connect.
|
||||
for (ai = ai_arg; ai; ai = ai->ai_next) {
|
||||
fd = (ai->ai_next ? socket : xsocket)(ai->ai_family, ai->ai_socktype,
|
||||
ai->ai_protocol);
|
||||
xsetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
if (!(dobind ? bind : connect)(fd, ai->ai_addr, ai->ai_addrlen)) break;
|
||||
else if (!ai->ai_next) perror_exit_raw(dobind ? "bind" : "connect");
|
||||
close(fd);
|
||||
}
|
||||
freeaddrinfo(ai_arg);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int xconnectany(struct addrinfo *ai)
|
||||
{
|
||||
return xconnbind(ai, 0);
|
||||
}
|
||||
|
||||
|
||||
int xbindany(struct addrinfo *ai)
|
||||
{
|
||||
return xconnbind(ai, 1);
|
||||
}
|
||||
|
||||
void xbind(int fd, const struct sockaddr *sa, socklen_t len)
|
||||
{
|
||||
if (bind(fd, sa, len)) perror_exit("bind");
|
||||
}
|
||||
|
||||
void xconnect(int fd, const struct sockaddr *sa, socklen_t len)
|
||||
{
|
||||
if (connect(fd, sa, len)) perror_exit("connect");
|
||||
}
|
||||
|
||||
int xpoll(struct pollfd *fds, int nfds, int timeout)
|
||||
{
|
||||
int i;
|
||||
long long now, then = timeout>0 ? millitime() : 0;
|
||||
|
||||
for (;;) {
|
||||
if (0<=(i = poll(fds, nfds, timeout)) || toys.signal) return i;
|
||||
if (errno != EINTR && errno != ENOMEM) perror_exit("xpoll");
|
||||
else {
|
||||
now = millitime();
|
||||
timeout -= now-then;
|
||||
then = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop forwarding data from in1 to out1 and in2 to out2, handling
|
||||
// half-connection shutdown. timeouts return if no data for X ms.
|
||||
// Returns 0: both closed, 1 shutdown_timeout, 2 timeout
|
||||
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout)
|
||||
{
|
||||
struct pollfd pollfds[2];
|
||||
int i, pollcount = 2;
|
||||
|
||||
memset(pollfds, 0, 2*sizeof(struct pollfd));
|
||||
pollfds[0].events = pollfds[1].events = POLLIN;
|
||||
pollfds[0].fd = in1;
|
||||
pollfds[1].fd = in2;
|
||||
|
||||
// Poll loop copying data from each fd to the other one.
|
||||
for (;;) {
|
||||
if (!xpoll(pollfds, pollcount, timeout)) return pollcount;
|
||||
|
||||
for (i=0; i<pollcount; i++) {
|
||||
if (pollfds[i].revents & POLLIN) {
|
||||
int len = read(pollfds[i].fd, libbuf, sizeof(libbuf));
|
||||
if (len<1) pollfds[i].revents = POLLHUP;
|
||||
else xwrite(i ? out2 : out1, libbuf, len);
|
||||
}
|
||||
if (pollfds[i].revents & POLLHUP) {
|
||||
// Close half-connection. This is needed for things like
|
||||
// "echo GET / | netcat landley.net 80"
|
||||
// Note that in1 closing triggers timeout, in2 returns now.
|
||||
if (i) {
|
||||
shutdown(pollfds[0].fd, SHUT_WR);
|
||||
pollcount--;
|
||||
timeout = shutdown_timeout;
|
||||
} else return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return converted ipv4/ipv6 numeric address in libbuf
|
||||
char *ntop(struct sockaddr *sa)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
if (sa->sa_family == AF_INET) addr = &((struct sockaddr_in *)sa)->sin_addr;
|
||||
else addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
|
||||
inet_ntop(sa->sa_family, addr, libbuf, sizeof(libbuf));
|
||||
|
||||
return libbuf;
|
||||
}
|
||||
|
||||
void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest)
|
||||
{
|
||||
int rc = sendto(sockfd, buf, len, 0, dest,
|
||||
dest->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
|
||||
sizeof(struct sockaddr_in6));
|
||||
|
||||
if (rc != len) perror_exit("sendto");
|
||||
}
|
||||
|
||||
// xrecvfrom with timeout in milliseconds
|
||||
int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout)
|
||||
{
|
||||
socklen_t sl = sizeof(*sa);
|
||||
|
||||
if (timeout >= 0) {
|
||||
struct pollfd pfd;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
if (!xpoll(&pfd, 1, timeout)) return 0;
|
||||
}
|
||||
|
||||
len = recvfrom(fd, buf, len, 0, (void *)sa, &sl);
|
||||
if (len<0) perror_exit("recvfrom");
|
||||
|
||||
return len;
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/* password.c - password read/update helper functions.
|
||||
*
|
||||
* Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
|
||||
*
|
||||
* TODO: cleanup
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
#include <time.h>
|
||||
|
||||
// generate ID prefix and random salt for given encryption algorithm.
|
||||
int get_salt(char *salt, char *algo)
|
||||
{
|
||||
struct {
|
||||
char *type, id, len;
|
||||
} al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(al); i++) {
|
||||
if (!strcmp(algo, al[i].type)) {
|
||||
int len = al[i].len;
|
||||
char *s = salt;
|
||||
|
||||
if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
|
||||
|
||||
// Read appropriate number of random bytes for salt
|
||||
xgetrandom(libbuf, ((len*6)+7)/8, 0);
|
||||
|
||||
// Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
|
||||
for (i=0; i<len; i++) {
|
||||
int bitpos = i*6, bits = bitpos/8;
|
||||
|
||||
bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
|
||||
bits += 46;
|
||||
if (bits > 57) bits += 7;
|
||||
if (bits > 90) bits += 6;
|
||||
|
||||
s[i] = bits;
|
||||
}
|
||||
salt[len] = 0;
|
||||
|
||||
return s-salt;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Prompt with mesg, read password into buf, return 0 for success 1 for fail
|
||||
int read_password(char *buf, int buflen, char *mesg)
|
||||
{
|
||||
struct termios oldtermio;
|
||||
struct sigaction sa, oldsa;
|
||||
int i, ret = 1;
|
||||
|
||||
// NOP signal handler to return from the read. Use sigaction() instead
|
||||
// of xsignal() because we want to restore the old handler afterwards.
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = generic_signal;
|
||||
sigaction(SIGINT, &sa, &oldsa);
|
||||
|
||||
tcflush(0, TCIFLUSH);
|
||||
xset_terminal(0, 1, 0, &oldtermio);
|
||||
|
||||
xprintf("%s", mesg);
|
||||
|
||||
for (i=0; i < buflen-1; i++) {
|
||||
if ((ret = read(0, buf+i, 1)) < 0 || (!ret && !i)) {
|
||||
i = 0;
|
||||
ret = 1;
|
||||
|
||||
break;
|
||||
} else if (!ret || buf[i] == '\n' || buf[i] == '\r') {
|
||||
ret = 0;
|
||||
|
||||
break;
|
||||
} else if (buf[i] == 8 || buf[i] == 127) i -= i ? 2 : 1;
|
||||
}
|
||||
|
||||
// Restore terminal/signal state, terminate string
|
||||
sigaction(SIGINT, &oldsa, NULL);
|
||||
tcsetattr(0, TCSANOW, &oldtermio);
|
||||
buf[i] = 0;
|
||||
xputc('\n');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *get_nextcolon(char *line, int cnt)
|
||||
{
|
||||
while (cnt--) {
|
||||
if (!(line = strchr(line, ':'))) error_exit("Invalid Entry\n");
|
||||
line++; //jump past the colon
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
/*update_password is used by multiple utilities to update /etc/passwd,
|
||||
* /etc/shadow, /etc/group and /etc/gshadow files,
|
||||
* which are used as user, group databeses
|
||||
* entry can be
|
||||
* 1. encrypted password, when updating user password.
|
||||
* 2. complete entry for user details, when creating new user
|
||||
* 3. group members comma',' separated list, when adding user to group
|
||||
* 4. complete entry for group details, when creating new group
|
||||
* 5. entry = NULL, delete the named entry user/group
|
||||
*/
|
||||
int update_password(char *filename, char* username, char* entry)
|
||||
{
|
||||
char *filenamesfx = NULL, *namesfx = NULL, *shadow = NULL,
|
||||
*sfx = NULL, *line = NULL;
|
||||
FILE *exfp, *newfp;
|
||||
int ret = -1, found = 0, n;
|
||||
struct flock lock;
|
||||
size_t allocated_length;
|
||||
|
||||
shadow = strstr(filename, "shadow");
|
||||
filenamesfx = xmprintf("%s+", filename);
|
||||
sfx = strchr(filenamesfx, '+');
|
||||
|
||||
exfp = fopen(filename, "r+");
|
||||
if (!exfp) {
|
||||
perror_msg("Couldn't open file %s",filename);
|
||||
goto free_storage;
|
||||
}
|
||||
|
||||
*sfx = '-';
|
||||
unlink(filenamesfx);
|
||||
ret = link(filename, filenamesfx);
|
||||
if (ret < 0) error_msg("can't create backup file");
|
||||
|
||||
*sfx = '+';
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
|
||||
ret = fcntl(fileno(exfp), F_SETLK, &lock);
|
||||
if (ret < 0) perror_msg("Couldn't lock file %s",filename);
|
||||
|
||||
lock.l_type = F_UNLCK; //unlocking at a later stage
|
||||
|
||||
newfp = fopen(filenamesfx, "w+");
|
||||
if (!newfp) {
|
||||
error_msg("couldn't open file for writing");
|
||||
ret = -1;
|
||||
fclose(exfp);
|
||||
goto free_storage;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
namesfx = xmprintf("%s:",username);
|
||||
while ((n = getline(&line, &allocated_length, exfp)) > 0) {
|
||||
line[n-1] = 0;
|
||||
if (strncmp(line, namesfx, strlen(namesfx)))
|
||||
fprintf(newfp, "%s\n", line);
|
||||
else if (entry) {
|
||||
char *current_ptr = NULL;
|
||||
|
||||
found = 1;
|
||||
if (!strcmp(toys.which->name, "passwd")) {
|
||||
fprintf(newfp, "%s%s:",namesfx, entry);
|
||||
current_ptr = get_nextcolon(line, 2); //past passwd
|
||||
if (shadow) {
|
||||
fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60));
|
||||
current_ptr = get_nextcolon(current_ptr, 1);
|
||||
fprintf(newfp, "%s\n",current_ptr);
|
||||
} else fprintf(newfp, "%s\n",current_ptr);
|
||||
} else if (!strcmp(toys.which->name, "groupadd") ||
|
||||
!strcmp(toys.which->name, "addgroup") ||
|
||||
!strcmp(toys.which->name, "delgroup") ||
|
||||
!strcmp(toys.which->name, "groupdel")){
|
||||
current_ptr = get_nextcolon(line, 3); //past gid/admin list
|
||||
*current_ptr = '\0';
|
||||
fprintf(newfp, "%s", line);
|
||||
fprintf(newfp, "%s\n", entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
free(namesfx);
|
||||
if (!found && entry) fprintf(newfp, "%s\n", entry);
|
||||
fcntl(fileno(exfp), F_SETLK, &lock);
|
||||
fclose(exfp);
|
||||
|
||||
errno = 0;
|
||||
fflush(newfp);
|
||||
fsync(fileno(newfp));
|
||||
fclose(newfp);
|
||||
rename(filenamesfx, filename);
|
||||
if (errno) {
|
||||
perror_msg("File Writing/Saving failed: ");
|
||||
unlink(filenamesfx);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
free_storage:
|
||||
free(filenamesfx);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// pending.h - header for pending.c
|
||||
|
||||
// password.c
|
||||
#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0'
|
||||
int read_password(char * buff, int buflen, char* mesg);
|
||||
int update_password(char *filename, char* username, char* encrypted);
|
||||
|
||||
// lib.c
|
||||
// This should be switched to posix-2008 getline()
|
||||
char *get_line(int fd);
|
||||
|
||||
|
||||
// TODO this goes away when lib/password.c cleaned up
|
||||
@@ -0,0 +1,500 @@
|
||||
/* portability.c - code to workaround the deficiencies of various platforms.
|
||||
*
|
||||
* Copyright 2012 Rob Landley <rob@landley.net>
|
||||
* Copyright 2012 Georgi Chorbadzhiyski <gf@unixsol.org>
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// We can't fork() on nommu systems, and vfork() requires an exec() or exit()
|
||||
// before resuming the parent (because they share a heap until then). And no,
|
||||
// we can't implement our own clone() call that does the equivalent of fork()
|
||||
// because nommu heaps use physical addresses so if we copy the heap all our
|
||||
// pointers are wrong. (You need an mmu in order to map two heaps to the same
|
||||
// address range without interfering with each other.) In the absence of
|
||||
// a portable way to tell malloc() to start a new heap without freeing the old
|
||||
// one, you pretty much need the exec().)
|
||||
|
||||
// So we exec ourselves (via /proc/self/exe, if anybody knows a way to
|
||||
// re-exec self without depending on the filesystem, I'm all ears),
|
||||
// and use the arguments to signal reentry.
|
||||
|
||||
#if CFG_TOYBOX_FORK
|
||||
pid_t xfork(void)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) perror_exit("fork");
|
||||
|
||||
return pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
int xgetrandom(void *buf, unsigned buflen, unsigned flags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#if CFG_TOYBOX_GETRANDOM
|
||||
if (buflen == getrandom(buf, buflen, flags&~WARN_ONLY)) return 1;
|
||||
if (errno!=ENOSYS && !(flags&WARN_ONLY)) perror_exit("getrandom");
|
||||
#endif
|
||||
fd = xopen(flags ? "/dev/random" : "/dev/urandom",O_RDONLY|(flags&WARN_ONLY));
|
||||
if (fd == -1) return 0;
|
||||
xreadall(fd, buf, buflen);
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get list of mounted filesystems, including stat and statvfs info.
|
||||
// Returns a reversed list, which is good for finding overmounts and such.
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
struct mtab_list *xgetmountlist(char *path)
|
||||
{
|
||||
struct mtab_list *mtlist = 0, *mt;
|
||||
struct statfs *entries;
|
||||
int i, count;
|
||||
|
||||
if (path) error_exit("xgetmountlist");
|
||||
if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo");
|
||||
|
||||
// The "test" part of the loop is done before the first time through and
|
||||
// again after each "increment", so putting the actual load there avoids
|
||||
// duplicating it. If the load was NULL, the loop stops.
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
struct statfs *me = &entries[i];
|
||||
|
||||
mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) +
|
||||
strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4);
|
||||
dlist_add_nomalloc((void *)&mtlist, (void *)mt);
|
||||
|
||||
// Collect details about mounted filesystem.
|
||||
// Don't report errors, just leave data zeroed.
|
||||
stat(me->f_mntonname, &(mt->stat));
|
||||
statvfs(me->f_mntonname, &(mt->statvfs));
|
||||
|
||||
// Remember information from struct statfs.
|
||||
mt->dir = stpcpy(mt->type, me->f_fstypename)+1;
|
||||
mt->device = stpcpy(mt->dir, me->f_mntonname)+1;
|
||||
mt->opts = stpcpy(mt->device, me->f_mntfromname)+1;
|
||||
strcpy(mt->opts, ""); /* TODO: reverse from f_flags? */
|
||||
}
|
||||
|
||||
return mtlist;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <mntent.h>
|
||||
|
||||
static void octal_deslash(char *s)
|
||||
{
|
||||
char *o = s;
|
||||
|
||||
while (*s) {
|
||||
if (*s == '\\') {
|
||||
int i, oct = 0;
|
||||
|
||||
for (i = 1; i < 4; i++) {
|
||||
if (!isdigit(s[i])) break;
|
||||
oct = (oct<<3)+s[i]-'0';
|
||||
}
|
||||
if (i == 4) {
|
||||
*o++ = oct;
|
||||
s += i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*o++ = *s++;
|
||||
}
|
||||
|
||||
*o = 0;
|
||||
}
|
||||
|
||||
// Check if this type matches list.
|
||||
// Odd syntax: typelist all yes = if any, typelist all no = if none.
|
||||
|
||||
int mountlist_istype(struct mtab_list *ml, char *typelist)
|
||||
{
|
||||
int len, skip;
|
||||
char *t;
|
||||
|
||||
if (!typelist) return 1;
|
||||
|
||||
skip = strncmp(typelist, "no", 2);
|
||||
|
||||
for (;;) {
|
||||
if (!(t = comma_iterate(&typelist, &len))) break;
|
||||
if (!skip) {
|
||||
// If one -t starts with "no", the rest must too
|
||||
if (strncmp(t, "no", 2)) error_exit("bad typelist");
|
||||
if (!strncmp(t+2, ml->type, len-2)) {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
} else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
|
||||
skip = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !skip;
|
||||
}
|
||||
|
||||
struct mtab_list *xgetmountlist(char *path)
|
||||
{
|
||||
struct mtab_list *mtlist = 0, *mt;
|
||||
struct mntent *me;
|
||||
FILE *fp;
|
||||
char *p = path ? path : "/proc/mounts";
|
||||
|
||||
if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
|
||||
|
||||
// The "test" part of the loop is done before the first time through and
|
||||
// again after each "increment", so putting the actual load there avoids
|
||||
// duplicating it. If the load was NULL, the loop stops.
|
||||
|
||||
while ((me = getmntent(fp))) {
|
||||
mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
|
||||
strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
|
||||
dlist_add_nomalloc((void *)&mtlist, (void *)mt);
|
||||
|
||||
// Collect details about mounted filesystem
|
||||
// Don't report errors, just leave data zeroed
|
||||
if (!path) {
|
||||
stat(me->mnt_dir, &(mt->stat));
|
||||
statvfs(me->mnt_dir, &(mt->statvfs));
|
||||
}
|
||||
|
||||
// Remember information from /proc/mounts
|
||||
mt->dir = stpcpy(mt->type, me->mnt_type)+1;
|
||||
mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
|
||||
mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
|
||||
strcpy(mt->opts, me->mnt_opts);
|
||||
|
||||
octal_deslash(mt->dir);
|
||||
octal_deslash(mt->device);
|
||||
}
|
||||
endmntent(fp);
|
||||
|
||||
return mtlist;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <sys/event.h>
|
||||
|
||||
struct xnotify *xnotify_init(int max)
|
||||
{
|
||||
struct xnotify *not = xzalloc(sizeof(struct xnotify));
|
||||
|
||||
not->max = max;
|
||||
if ((not->kq = kqueue()) == -1) perror_exit("kqueue");
|
||||
not->paths = xmalloc(max * sizeof(char *));
|
||||
not->fds = xmalloc(max * sizeof(int));
|
||||
|
||||
return not;
|
||||
}
|
||||
|
||||
int xnotify_add(struct xnotify *not, int fd, char *path)
|
||||
{
|
||||
struct kevent event;
|
||||
|
||||
if (not->count == not->max) error_exit("xnotify_add overflow");
|
||||
EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
|
||||
if (kevent(not->kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR)
|
||||
return -1;
|
||||
not->paths[not->count] = path;
|
||||
not->fds[not->count++] = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xnotify_wait(struct xnotify *not, char **path)
|
||||
{
|
||||
struct kevent event;
|
||||
int i;
|
||||
|
||||
for (;;) {
|
||||
if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) {
|
||||
// We get the fd for free, but still have to search for the path.
|
||||
for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) {
|
||||
*path = not->paths[i];
|
||||
|
||||
return event.ident;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/inotify.h>
|
||||
|
||||
struct xnotify *xnotify_init(int max)
|
||||
{
|
||||
struct xnotify *not = xzalloc(sizeof(struct xnotify));
|
||||
|
||||
not->max = max;
|
||||
if ((not->kq = inotify_init()) < 0) perror_exit("inotify_init");
|
||||
not->paths = xmalloc(max * sizeof(char *));
|
||||
not->fds = xmalloc(max * 2 * sizeof(int));
|
||||
|
||||
return not;
|
||||
}
|
||||
|
||||
int xnotify_add(struct xnotify *not, int fd, char *path)
|
||||
{
|
||||
int i = 2*not->count;
|
||||
|
||||
if (not->max == not->count) error_exit("xnotify_add overflow");
|
||||
if ((not->fds[i] = inotify_add_watch(not->kq, path, IN_MODIFY))==-1)
|
||||
return -1;
|
||||
not->fds[i+1] = fd;
|
||||
not->paths[not->count++] = path;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xnotify_wait(struct xnotify *not, char **path)
|
||||
{
|
||||
struct inotify_event ev;
|
||||
int i;
|
||||
|
||||
for (;;) {
|
||||
if (sizeof(ev)!=read(not->kq, &ev, sizeof(ev))) perror_exit("inotify");
|
||||
|
||||
for (i = 0; i<not->count; i++) if (ev.wd==not->fds[2*i]) {
|
||||
*path = not->paths[i];
|
||||
|
||||
return not->fds[2*i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size, 0, 0);
|
||||
}
|
||||
|
||||
ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(fd, name, value, size, 0, 0);
|
||||
}
|
||||
|
||||
ssize_t xattr_list(const char *path, char *list, size_t size)
|
||||
{
|
||||
return listxattr(path, list, size, 0);
|
||||
}
|
||||
|
||||
ssize_t xattr_llist(const char *path, char *list, size_t size)
|
||||
{
|
||||
return listxattr(path, list, size, XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t xattr_flist(int fd, char *list, size_t size)
|
||||
{
|
||||
return flistxattr(fd, list, size, 0);
|
||||
}
|
||||
|
||||
ssize_t xattr_set(const char* path, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, flags);
|
||||
}
|
||||
|
||||
ssize_t xattr_lset(const char* path, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
|
||||
}
|
||||
|
||||
ssize_t xattr_fset(int fd, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return fsetxattr(fd, name, value, size, 0, flags);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return lgetxattr(path, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(fd, name, value, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_list(const char *path, char *list, size_t size)
|
||||
{
|
||||
return listxattr(path, list, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_llist(const char *path, char *list, size_t size)
|
||||
{
|
||||
return llistxattr(path, list, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_flist(int fd, char *list, size_t size)
|
||||
{
|
||||
return flistxattr(fd, list, size);
|
||||
}
|
||||
|
||||
ssize_t xattr_set(const char* path, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return setxattr(path, name, value, size, flags);
|
||||
}
|
||||
|
||||
ssize_t xattr_lset(const char* path, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return lsetxattr(path, name, value, size, flags);
|
||||
}
|
||||
|
||||
ssize_t xattr_fset(int fd, const char* name,
|
||||
const void* value, size_t size, int flags)
|
||||
{
|
||||
return fsetxattr(fd, name, value, size, flags);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
// In the absence of a mknodat system call, fchdir to dirfd and back
|
||||
// around a regular mknod call...
|
||||
int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
|
||||
{
|
||||
int old_dirfd = open(".", O_RDONLY), result;
|
||||
|
||||
if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1;
|
||||
result = mknod(path, mode, dev);
|
||||
if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return");
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Signals required by POSIX 2008:
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
|
||||
|
||||
#define SIGNIFY(x) {SIG##x, #x}
|
||||
|
||||
static const struct signame signames[] = {
|
||||
// POSIX
|
||||
SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
|
||||
SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
|
||||
SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
|
||||
SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
|
||||
SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
|
||||
// Non-POSIX signals that cause termination
|
||||
SIGNIFY(PROF), SIGNIFY(IO),
|
||||
#ifdef __linux__
|
||||
SIGNIFY(STKFLT), SIGNIFY(POLL), SIGNIFY(PWR),
|
||||
#elif defined(__APPLE__)
|
||||
SIGNIFY(EMT), SIGNIFY(INFO),
|
||||
#endif
|
||||
|
||||
// Note: sigatexit relies on all the signals with a default disposition that
|
||||
// terminates the process coming *before* SIGCHLD.
|
||||
|
||||
// POSIX signals that don't cause termination
|
||||
SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
|
||||
SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG),
|
||||
// Non-POSIX signals that don't cause termination
|
||||
SIGNIFY(WINCH),
|
||||
};
|
||||
int signames_len = ARRAY_LEN(signames);
|
||||
|
||||
#undef SIGNIFY
|
||||
|
||||
void xsignal_all_killers(void *handler)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; signames[i].num != SIGCHLD; i++)
|
||||
if (signames[i].num != SIGKILL)
|
||||
xsignal(signames[i].num, handler ? exit_signal : SIG_DFL);
|
||||
}
|
||||
|
||||
// Convert a string like "9", "KILL", "SIGHUP", or "SIGRTMIN+2" to a number.
|
||||
int sig_to_num(char *sigstr)
|
||||
{
|
||||
int i, offset;
|
||||
char *s;
|
||||
|
||||
// Numeric?
|
||||
i = estrtol(sigstr, &s, 10);
|
||||
if (!errno && !*s) return i;
|
||||
|
||||
// Skip leading "SIG".
|
||||
strcasestart(&sigstr, "sig");
|
||||
|
||||
// Named signal?
|
||||
for (i=0; i<ARRAY_LEN(signames); i++)
|
||||
if (!strcasecmp(sigstr, signames[i].name)) return signames[i].num;
|
||||
|
||||
// Real-time signal?
|
||||
#ifdef SIGRTMIN
|
||||
if (strcasestart(&sigstr, "rtmin")) i = SIGRTMIN;
|
||||
else if (strcasestart(&sigstr, "rtmax")) i = SIGRTMAX;
|
||||
else return -1;
|
||||
|
||||
// No offset?
|
||||
if (!*sigstr) return i;
|
||||
|
||||
// We allow any offset that's still a real-time signal: SIGRTMIN+20 is fine.
|
||||
// Others are more restrictive, only accepting what they show with -l.
|
||||
offset = estrtol(sigstr, &s, 10);
|
||||
if (errno || *s) return -1;
|
||||
i += offset;
|
||||
if (i >= SIGRTMIN && i <= SIGRTMAX) return i;
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *num_to_sig(int sig)
|
||||
{
|
||||
int i;
|
||||
|
||||
// A named signal?
|
||||
for (i=0; i<signames_len; i++)
|
||||
if (signames[i].num == sig) return signames[i].name;
|
||||
|
||||
// A real-time signal?
|
||||
#ifdef SIGRTMIN
|
||||
if (sig == SIGRTMIN) return "RTMIN";
|
||||
if (sig == SIGRTMAX) return "RTMAX";
|
||||
if (sig > SIGRTMIN && sig < SIGRTMAX) {
|
||||
if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN);
|
||||
else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig);
|
||||
return libbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
// Workarounds for horrible build environment idiosyncrasies.
|
||||
|
||||
// Instead of polluting the code with strange #ifdefs to work around bugs
|
||||
// in specific compiler, library, or OS versions, localize all that here
|
||||
// and in portability.c
|
||||
|
||||
// For musl
|
||||
#define _ALL_SOURCE
|
||||
#ifndef REG_STARTEND
|
||||
#define REG_STARTEND 0
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
// macOS 10.13 doesn't have the POSIX 2008 direct access to timespec in
|
||||
// struct stat, but we can ask it to give us something equivalent...
|
||||
// (This must come before any #include!)
|
||||
#define _DARWIN_C_SOURCE
|
||||
// ...and then use macros to paper over the difference.
|
||||
#define st_atim st_atimespec
|
||||
#define st_ctim st_ctimespec
|
||||
#define st_mtim st_mtimespec
|
||||
#endif
|
||||
|
||||
// Test for gcc (using compiler builtin #define)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define printf_format __attribute__((format(printf, 1, 2)))
|
||||
#else
|
||||
#define printf_format
|
||||
#endif
|
||||
|
||||
// Always use long file support.
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
// This isn't in the spec, but it's how we determine what libc we're using.
|
||||
|
||||
// Types various replacement prototypes need.
|
||||
// This also lets us determine what libc we're using. Systems that
|
||||
// have <features.h> will transitively include it, and ones that don't --
|
||||
// macOS -- won't break.
|
||||
#include <sys/types.h>
|
||||
|
||||
// Various constants old build environments might not have even if kernel does
|
||||
|
||||
#ifndef AT_FDCWD
|
||||
#define AT_FDCWD -100
|
||||
#endif
|
||||
|
||||
#ifndef AT_SYMLINK_NOFOLLOW
|
||||
#define AT_SYMLINK_NOFOLLOW 0x100
|
||||
#endif
|
||||
|
||||
#ifndef AT_REMOVEDIR
|
||||
#define AT_REMOVEDIR 0x200
|
||||
#endif
|
||||
|
||||
#ifndef RLIMIT_RTTIME
|
||||
#define RLIMIT_RTTIME 15
|
||||
#endif
|
||||
|
||||
// Introduced in Linux 3.1
|
||||
#ifndef SEEK_DATA
|
||||
#define SEEK_DATA 3
|
||||
#endif
|
||||
#ifndef SEEK_HOLE
|
||||
#define SEEK_HOLE 4
|
||||
#endif
|
||||
|
||||
// We don't define GNU_dammit because we're not part of the gnu project, and
|
||||
// don't want to get any FSF on us. Unfortunately glibc (gnu libc)
|
||||
// won't give us Linux syscall wrappers without claiming to be part of the
|
||||
// gnu project (because Stallman's "GNU owns Linux" revisionist history
|
||||
// crusade includes the kernel, even though Linux was inspired by Minix).
|
||||
|
||||
// We use most non-posix Linux syscalls directly through the syscall() wrapper,
|
||||
// but even many posix-2008 functions aren't provided by glibc unless you
|
||||
// claim it's in the name of Gnu.
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
// "Function prototypes shall be provided." but aren't.
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html
|
||||
char *crypt(const char *key, const char *salt);
|
||||
|
||||
// According to posix, #include header, get a function definition. But glibc...
|
||||
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/wcwidth.html
|
||||
#include <wchar.h>
|
||||
int wcwidth(wchar_t wc);
|
||||
|
||||
// see http://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html
|
||||
#include <time.h>
|
||||
char *strptime(const char *buf, const char *format, struct tm *tm);
|
||||
|
||||
// They didn't like posix basename so they defined another function with the
|
||||
// same name and if you include libgen.h it #defines basename to something
|
||||
// else (where they implemented the real basename), and that define breaks
|
||||
// the table entry for the basename command. They didn't make a new function
|
||||
// with a different name for their new behavior because gnu.
|
||||
//
|
||||
// Solution: don't use their broken header, provide an inline to redirect the
|
||||
// correct name to the broken name.
|
||||
|
||||
char *dirname(char *path);
|
||||
char *__xpg_basename(char *path);
|
||||
static inline char *basename(char *path) { return __xpg_basename(path); }
|
||||
char *strcasestr(const char *haystack, const char *needle);
|
||||
#endif // defined(glibc)
|
||||
|
||||
#if !defined(__GLIBC__)
|
||||
// POSIX basename.
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
// Work out how to do endianness
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#define bswap_16(x) OSSwapInt16(x)
|
||||
#define bswap_32(x) OSSwapInt32(x)
|
||||
#define bswap_64(x) OSSwapInt64(x)
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
#include <sys/endian.h>
|
||||
|
||||
#if _BYTE_ORDER == _BIG_ENDIAN
|
||||
#define IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <endian.h>
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define IS_BIG_ENDIAN 1
|
||||
#else
|
||||
#define IS_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if IS_BIG_ENDIAN
|
||||
#define IS_LITTLE_ENDIAN 0
|
||||
#define SWAP_BE16(x) (x)
|
||||
#define SWAP_BE32(x) (x)
|
||||
#define SWAP_BE64(x) (x)
|
||||
#define SWAP_LE16(x) bswap_16(x)
|
||||
#define SWAP_LE32(x) bswap_32(x)
|
||||
#define SWAP_LE64(x) bswap_64(x)
|
||||
#else
|
||||
#define IS_LITTLE_ENDIAN 1
|
||||
#define SWAP_BE16(x) bswap_16(x)
|
||||
#define SWAP_BE32(x) bswap_32(x)
|
||||
#define SWAP_BE64(x) bswap_64(x)
|
||||
#define SWAP_LE16(x) (x)
|
||||
#define SWAP_LE32(x) (x)
|
||||
#define SWAP_LE64(x) (x)
|
||||
#endif
|
||||
|
||||
// Linux headers not listed by POSIX or LSB
|
||||
#include <sys/mount.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/swap.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <util.h>
|
||||
#elif !defined(__FreeBSD__)
|
||||
#include <pty.h>
|
||||
#else
|
||||
#include <termios.h>
|
||||
#ifndef IUTF8
|
||||
#define IUTF8 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
// Linux and macOS has both have getxattr and friends in <sys/xattr.h>, but
|
||||
// they aren't compatible.
|
||||
#include <sys/xattr.h>
|
||||
ssize_t xattr_get(const char *, const char *, void *, size_t);
|
||||
ssize_t xattr_lget(const char *, const char *, void *, size_t);
|
||||
ssize_t xattr_fget(int fd, const char *, void *, size_t);
|
||||
ssize_t xattr_list(const char *, char *, size_t);
|
||||
ssize_t xattr_llist(const char *, char *, size_t);
|
||||
ssize_t xattr_flist(int, char *, size_t);
|
||||
ssize_t xattr_set(const char*, const char*, const void*, size_t, int);
|
||||
ssize_t xattr_lset(const char*, const char*, const void*, size_t, int);
|
||||
ssize_t xattr_fset(int, const char*, const void*, size_t, int);
|
||||
#endif
|
||||
|
||||
// macOS doesn't have mknodat, but we can fake it.
|
||||
#ifdef __APPLE__
|
||||
int mknodat(int, const char*, mode_t, dev_t);
|
||||
#endif
|
||||
|
||||
// Android is missing some headers and functions
|
||||
// "generated/config.h" is included first
|
||||
#if CFG_TOYBOX_SHADOW
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
#if CFG_TOYBOX_UTMPX
|
||||
#include <utmpx.h>
|
||||
#else
|
||||
struct utmpx {int ut_type;};
|
||||
#define USER_PROCESS 0
|
||||
static inline struct utmpx *getutxent(void) {return 0;}
|
||||
static inline void setutxent(void) {;}
|
||||
static inline void endutxent(void) {;}
|
||||
#endif
|
||||
|
||||
// Some systems don't define O_NOFOLLOW, and it varies by architecture, so...
|
||||
#include <fcntl.h>
|
||||
#ifndef O_NOFOLLOW
|
||||
#define O_NOFOLLOW 0
|
||||
#endif
|
||||
#ifndef O_NOATIME
|
||||
#define O_NOATIME 01000000
|
||||
#endif
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 02000000
|
||||
#endif
|
||||
#ifndef O_PATH
|
||||
#define O_PATH 010000000
|
||||
#endif
|
||||
#ifndef SCHED_RESET_ON_FORK
|
||||
#define SCHED_RESET_ON_FORK (1<<30)
|
||||
#endif
|
||||
|
||||
// Glibc won't give you linux-kernel constants unless you say "no, a BUD lite"
|
||||
// even though linux has nothing to do with the FSF and never has.
|
||||
#ifndef F_SETPIPE_SZ
|
||||
#define F_SETPIPE_SZ 1031
|
||||
#endif
|
||||
|
||||
#ifndef F_GETPIPE_SZ
|
||||
#define F_GETPIPE_SZ 1032
|
||||
#endif
|
||||
|
||||
#if defined(__SIZEOF_DOUBLE__) && defined(__SIZEOF_LONG__) \
|
||||
&& __SIZEOF_DOUBLE__ <= __SIZEOF_LONG__
|
||||
typedef double FLOAT;
|
||||
#else
|
||||
typedef float FLOAT;
|
||||
#endif
|
||||
|
||||
#ifndef __uClinux__
|
||||
pid_t xfork(void);
|
||||
#endif
|
||||
|
||||
//#define strncpy(...) @@strncpyisbadmmkay@@
|
||||
//#define strncat(...) @@strncatisbadmmkay@@
|
||||
|
||||
// Support building the Android tools on glibc, so hermetic AOSP builds can
|
||||
// use toybox before they're ready to switch to host bionic.
|
||||
#ifdef __BIONIC__
|
||||
#include <android/log.h>
|
||||
#else
|
||||
typedef enum android_LogPriority {
|
||||
ANDROID_LOG_UNKNOWN = 0,
|
||||
ANDROID_LOG_DEFAULT,
|
||||
ANDROID_LOG_VERBOSE,
|
||||
ANDROID_LOG_DEBUG,
|
||||
ANDROID_LOG_INFO,
|
||||
ANDROID_LOG_WARN,
|
||||
ANDROID_LOG_ERROR,
|
||||
ANDROID_LOG_FATAL,
|
||||
ANDROID_LOG_SILENT,
|
||||
} android_LogPriority;
|
||||
static inline int __android_log_write(int pri, const char *tag, const char *msg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// libprocessgroup is an Android platform library not included in the NDK.
|
||||
#if defined(__BIONIC__) && __has_include(<processgroup/sched_policy.h>)
|
||||
#include <processgroup/sched_policy.h>
|
||||
#else
|
||||
static inline int get_sched_policy(int tid, void *policy) {return 0;}
|
||||
static inline char *get_sched_policy_name(int policy) {return "unknown";}
|
||||
#endif
|
||||
|
||||
// Android NDKv18 has liblog.so but not liblog.c for static builds,
|
||||
// stub it out for now.
|
||||
#ifdef __ANDROID_NDK__
|
||||
#define __android_log_write(a, b, c) (0)
|
||||
#define adjtime(x, y) (0)
|
||||
#endif
|
||||
|
||||
#ifndef SYSLOG_NAMES
|
||||
typedef struct {char *c_name; int c_val;} CODE;
|
||||
extern CODE prioritynames[], facilitynames[];
|
||||
#endif
|
||||
|
||||
#if CFG_TOYBOX_GETRANDOM
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
int xgetrandom(void *buf, unsigned len, unsigned flags);
|
||||
|
||||
// Android's bionic libc doesn't have confstr.
|
||||
#ifdef __BIONIC__
|
||||
#define _CS_PATH 0
|
||||
#define _CS_V7_ENV 1
|
||||
#include <string.h>
|
||||
static inline void confstr(int a, char *b, int c) {strcpy(b, a ? "POSIXLY_CORRECT=1" : "/bin:/usr/bin");}
|
||||
#endif
|
||||
|
||||
// Paper over the differences between BSD kqueue and Linux inotify for tail.
|
||||
|
||||
struct xnotify {
|
||||
char **paths;
|
||||
int max, *fds, count, kq;
|
||||
};
|
||||
|
||||
struct xnotify *xnotify_init(int max);
|
||||
int xnotify_add(struct xnotify *not, int fd, char *path);
|
||||
int xnotify_wait(struct xnotify *not, char **path);
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define f_frsize f_iosize
|
||||
#endif
|
||||
|
||||
int sig_to_num(char *s);
|
||||
char *num_to_sig(int sig);
|
||||
|
||||
struct signame {
|
||||
int num;
|
||||
char *name;
|
||||
};
|
||||
void xsignal_all_killers(void *handler);
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Flags values for the third argument of NEWTOY()
|
||||
*
|
||||
* Included from both main.c (runs in toys.h context) and scripts/install.c
|
||||
* (which may build on crazy things like macosx when cross compiling).
|
||||
*/
|
||||
|
||||
// Flags describing command behavior.
|
||||
|
||||
// Where to install (toybox --long outputs absolute paths to commands)
|
||||
// If no location bits set, command not listed in "toybox" command's output.
|
||||
#define TOYFLAG_USR (1<<0)
|
||||
#define TOYFLAG_BIN (1<<1)
|
||||
#define TOYFLAG_SBIN (1<<2)
|
||||
#define TOYMASK_LOCATION ((1<<4)-1)
|
||||
|
||||
// This is a shell built-in function, running in the same process context.
|
||||
#define TOYFLAG_NOFORK (1<<4)
|
||||
#define TOYFLAG_MAYFORK (1<<5)
|
||||
|
||||
// Start command with a umask of 0 (saves old umask in this.old_umask)
|
||||
#define TOYFLAG_UMASK (1<<6)
|
||||
|
||||
// This command runs as root.
|
||||
#define TOYFLAG_STAYROOT (1<<7) // Don't drop suid root before running cmd_main
|
||||
#define TOYFLAG_NEEDROOT (1<<8) // Refuse to run if real uid != 0
|
||||
#define TOYFLAG_ROOTONLY (TOYFLAG_STAYROOT|TOYFLAG_NEEDROOT)
|
||||
|
||||
// Call setlocale to listen to environment variables.
|
||||
// This invalidates sprintf("%.*s", size, string) as a valid length constraint.
|
||||
#define TOYFLAG_LOCALE (1<<9)
|
||||
|
||||
// Suppress default --help processing
|
||||
#define TOYFLAG_NOHELP (1<<10)
|
||||
|
||||
// Error code to return if argument parsing fails (default 1)
|
||||
#define TOYFLAG_ARGFAIL(x) (x<<24)
|
||||
|
||||
#if CFG_TOYBOX_PEDANTIC_ARGS
|
||||
#define NO_ARGS ">0"
|
||||
#else
|
||||
#define NO_ARGS 0
|
||||
#endif
|
||||
@@ -0,0 +1,282 @@
|
||||
/* interestingtimes.c - cursor control
|
||||
*
|
||||
* Copyright 2015 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
int tty_fd(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i<3; i++) if (isatty(j = (i+1)%3)) return j;
|
||||
|
||||
return notstdio(open("/dev/tty", O_RDWR));
|
||||
}
|
||||
|
||||
// Quick and dirty query size of terminal, doesn't do ANSI probe fallback.
|
||||
// set x=80 y=25 before calling to provide defaults. Returns 0 if couldn't
|
||||
// determine size.
|
||||
|
||||
int terminal_size(unsigned *xx, unsigned *yy)
|
||||
{
|
||||
struct winsize ws;
|
||||
unsigned i, x = 0, y = 0;
|
||||
char *s;
|
||||
|
||||
// stdin, stdout, stderr
|
||||
for (i=0; i<3; i++) {
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
if (isatty(i) && !ioctl(i, TIOCGWINSZ, &ws)) {
|
||||
if (ws.ws_col) x = ws.ws_col;
|
||||
if (ws.ws_row) y = ws.ws_row;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
s = getenv("COLUMNS");
|
||||
if (s) sscanf(s, "%u", &x);
|
||||
s = getenv("LINES");
|
||||
if (s) sscanf(s, "%u", &y);
|
||||
|
||||
// Never return 0 for either value, leave it at default instead.
|
||||
if (xx && x) *xx = x;
|
||||
if (yy && y) *yy = y;
|
||||
|
||||
return x || y;
|
||||
}
|
||||
|
||||
// Query terminal size, sending ANSI probe if necesary. (Probe queries xterm
|
||||
// size through serial connection, when local TTY doesn't know but remote does.)
|
||||
// Returns 0 if ANSI probe sent, 1 if size determined from tty or environment
|
||||
|
||||
int terminal_probesize(unsigned *xx, unsigned *yy)
|
||||
{
|
||||
if (terminal_size(xx, yy) && (!xx || *xx) && (!yy || *yy)) return 1;
|
||||
|
||||
// Send probe: bookmark cursor position, jump to bottom right,
|
||||
// query position, return cursor to bookmarked position.
|
||||
xprintf("\033[s\033[999C\033[999B\033[6n\033[u");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset terminal to known state, saving copy of old state if old != NULL.
|
||||
int set_terminal(int fd, int raw, int speed, struct termios *old)
|
||||
{
|
||||
struct termios termio;
|
||||
int i = tcgetattr(fd, &termio);
|
||||
|
||||
// Fetch local copy of old terminfo, and copy struct contents to *old if set
|
||||
if (i) return i;
|
||||
if (old) *old = termio;
|
||||
|
||||
// the following are the bits set for an xterm. Linux text mode TTYs by
|
||||
// default add two additional bits that only matter for serial processing
|
||||
// (turn serial line break into an interrupt, and XON/XOFF flow control)
|
||||
|
||||
// Any key unblocks output, swap CR and NL on input
|
||||
termio.c_iflag = IXANY|ICRNL|INLCR;
|
||||
if (toys.which->flags & TOYFLAG_LOCALE) termio.c_iflag |= IUTF8;
|
||||
|
||||
// Output appends CR to NL, does magic undocumented postprocessing
|
||||
termio.c_oflag = ONLCR|OPOST;
|
||||
|
||||
// Leave serial port speed alone
|
||||
// termio.c_cflag = C_READ|CS8|EXTB;
|
||||
|
||||
// Generate signals, input entire line at once, echo output
|
||||
// erase, line kill, escape control characters with ^
|
||||
// erase line char at a time
|
||||
// "extended" behavior: ctrl-V quotes next char, ctrl-R reprints unread chars,
|
||||
// ctrl-W erases word
|
||||
termio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
|
||||
|
||||
if (raw) cfmakeraw(&termio);
|
||||
|
||||
if (speed) {
|
||||
int i, speeds[] = {50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
|
||||
4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
|
||||
500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
|
||||
2500000, 3000000, 3500000, 4000000};
|
||||
|
||||
// Find speed in table, adjust to constant
|
||||
for (i = 0; i < ARRAY_LEN(speeds); i++) if (speeds[i] == speed) break;
|
||||
if (i == ARRAY_LEN(speeds)) error_exit("unknown speed: %d", speed);
|
||||
cfsetspeed(&termio, i+1+4081*(i>15));
|
||||
}
|
||||
|
||||
return tcsetattr(fd, TCSAFLUSH, &termio);
|
||||
}
|
||||
|
||||
void xset_terminal(int fd, int raw, int speed, struct termios *old)
|
||||
{
|
||||
if (-1 != set_terminal(fd, raw, speed, old)) return;
|
||||
|
||||
sprintf(libbuf, "/proc/self/fd/%d", fd);
|
||||
libbuf[readlink0(libbuf, libbuf, sizeof(libbuf))] = 0;
|
||||
perror_exit("tcsetattr %s", libbuf);
|
||||
}
|
||||
|
||||
struct scan_key_list {
|
||||
int key;
|
||||
char *seq;
|
||||
} static const scan_key_list[] = {
|
||||
{KEY_UP, "\033[A"}, {KEY_DOWN, "\033[B"},
|
||||
{KEY_RIGHT, "\033[C"}, {KEY_LEFT, "\033[D"},
|
||||
|
||||
{KEY_UP|KEY_SHIFT, "\033[1;2A"}, {KEY_DOWN|KEY_SHIFT, "\033[1;2B"},
|
||||
{KEY_RIGHT|KEY_SHIFT, "\033[1;2C"}, {KEY_LEFT|KEY_SHIFT, "\033[1;2D"},
|
||||
|
||||
{KEY_UP|KEY_ALT, "\033[1;3A"}, {KEY_DOWN|KEY_ALT, "\033[1;3B"},
|
||||
{KEY_RIGHT|KEY_ALT, "\033[1;3C"}, {KEY_LEFT|KEY_ALT, "\033[1;3D"},
|
||||
|
||||
{KEY_UP|KEY_CTRL, "\033[1;5A"}, {KEY_DOWN|KEY_CTRL, "\033[1;5B"},
|
||||
{KEY_RIGHT|KEY_CTRL, "\033[1;5C"}, {KEY_LEFT|KEY_CTRL, "\033[1;5D"},
|
||||
|
||||
// VT102/VT220 escapes.
|
||||
{KEY_HOME, "\033[1~"},
|
||||
{KEY_INSERT, "\033[2~"},
|
||||
{KEY_DELETE, "\033[3~"},
|
||||
{KEY_END, "\033[4~"},
|
||||
{KEY_PGUP, "\033[5~"},
|
||||
{KEY_PGDN, "\033[6~"},
|
||||
// "Normal" "PC" escapes (xterm).
|
||||
{KEY_HOME, "\033OH"},
|
||||
{KEY_END, "\033OF"},
|
||||
// "Application" "PC" escapes (gnome-terminal).
|
||||
{KEY_HOME, "\033[H"},
|
||||
{KEY_END, "\033[F"},
|
||||
|
||||
{KEY_FN+1, "\033OP"}, {KEY_FN+2, "\033OQ"}, {KEY_FN+3, "\033OR"},
|
||||
{KEY_FN+4, "\033OS"}, {KEY_FN+5, "\033[15~"}, {KEY_FN+6, "\033[17~"},
|
||||
{KEY_FN+7, "\033[18~"}, {KEY_FN+8, "\033[19~"}, {KEY_FN+9, "\033[20~"},
|
||||
};
|
||||
|
||||
// Scan stdin for a keypress, parsing known escape sequences, including
|
||||
// responses to screen size queries.
|
||||
// Blocks for timeout_ms milliseconds, 0=return immediately, -1=wait forever.
|
||||
// Returns 0-255=literal, -1=EOF, -2=TIMEOUT, -3=RESIZE, 256+= a KEY_ constant.
|
||||
// Scratch space is necessary because last char of !seq could start new seq.
|
||||
// Zero out first byte of scratch before first call to scan_key.
|
||||
int scan_key_getsize(char *scratch, int timeout_ms, unsigned *xx, unsigned *yy)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int maybe, i, j;
|
||||
char *test;
|
||||
|
||||
for (;;) {
|
||||
pfd.fd = 0;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
|
||||
maybe = 0;
|
||||
if (*scratch) {
|
||||
int pos[6];
|
||||
unsigned x, y;
|
||||
|
||||
// Check for return from terminal size probe
|
||||
memset(pos, 0, 6*sizeof(int));
|
||||
scratch[(1+*scratch)&15] = 0;
|
||||
sscanf(scratch+1, "\033%n[%n%3u%n;%n%3u%nR%n", pos, pos+1, &y,
|
||||
pos+2, pos+3, &x, pos+4, pos+5);
|
||||
if (pos[5]) {
|
||||
// Recognized X/Y position, consume and return
|
||||
*scratch = 0;
|
||||
if (xx) *xx = x;
|
||||
if (yy) *yy = y;
|
||||
return -3;
|
||||
} else for (i=0; i<6; i++) if (pos[i]==*scratch) maybe = 1;
|
||||
|
||||
// Check sequences
|
||||
for (i = 0; i<ARRAY_LEN(scan_key_list); i++) {
|
||||
test = scan_key_list[i].seq;
|
||||
for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break;
|
||||
if (j == *scratch) {
|
||||
maybe = 1;
|
||||
if (!test[j]) {
|
||||
// We recognized current sequence: consume and return
|
||||
*scratch = 0;
|
||||
return 256+scan_key_list[i].key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If current data can't be a known sequence, return next raw char
|
||||
if (!maybe) break;
|
||||
}
|
||||
|
||||
// Need more data to decide
|
||||
|
||||
// 30ms is about the gap between characters at 300 baud
|
||||
if (maybe || timeout_ms != -1)
|
||||
if (!xpoll(&pfd, 1, maybe ? 30 : timeout_ms)) break;
|
||||
|
||||
// Read 1 byte so we don't overshoot sequence match. (We can deviate
|
||||
// and fail to match, but match consumes entire buffer.)
|
||||
if (toys.signal>0 || 1 != read(0, scratch+1+*scratch, 1))
|
||||
return (toys.signal>0) ? -3 : -1;
|
||||
++*scratch;
|
||||
}
|
||||
|
||||
// Was not a sequence
|
||||
if (!*scratch) return -2;
|
||||
i = scratch[1];
|
||||
if (--*scratch) memmove(scratch+1, scratch+2, *scratch);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Wrapper that ignores results from ANSI probe to update screensize.
|
||||
// Otherwise acts like scan_key_getsize().
|
||||
int scan_key(char *scratch, int timeout_ms)
|
||||
{
|
||||
return scan_key_getsize(scratch, timeout_ms, NULL, NULL);
|
||||
}
|
||||
|
||||
void tty_esc(char *s)
|
||||
{
|
||||
printf("\033[%s", s);
|
||||
}
|
||||
|
||||
void tty_jump(int x, int y)
|
||||
{
|
||||
char s[32];
|
||||
|
||||
sprintf(s, "%d;%dH", y+1, x+1);
|
||||
tty_esc(s);
|
||||
}
|
||||
|
||||
void tty_reset(void)
|
||||
{
|
||||
set_terminal(0, 0, 0, 0);
|
||||
tty_esc("?25h");
|
||||
tty_esc("0m");
|
||||
tty_jump(0, 999);
|
||||
tty_esc("K");
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
// If you call set_terminal(), use sigatexit(tty_sigreset);
|
||||
void tty_sigreset(int i)
|
||||
{
|
||||
tty_reset();
|
||||
_exit(i ? 128+i : 0);
|
||||
}
|
||||
|
||||
void start_redraw(unsigned *width, unsigned *height)
|
||||
{
|
||||
// If never signaled, do raw mode setup.
|
||||
if (!toys.signal) {
|
||||
*width = 80;
|
||||
*height = 25;
|
||||
set_terminal(0, 1, 0, 0);
|
||||
sigatexit(tty_sigreset);
|
||||
xsignal(SIGWINCH, generic_signal);
|
||||
}
|
||||
if (toys.signal != -1) {
|
||||
toys.signal = -1;
|
||||
terminal_probesize(width, height);
|
||||
}
|
||||
xprintf("\033[H\033[J");
|
||||
}
|
||||
+1069
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
/* Toybox infrastructure.
|
||||
*
|
||||
* Copyright 2006 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
#ifndef TOYBOX_VERSION
|
||||
#ifndef TOYBOX_VENDOR
|
||||
#define TOYBOX_VENDOR ""
|
||||
#endif
|
||||
#define TOYBOX_VERSION "0.8.2"TOYBOX_VENDOR
|
||||
#endif
|
||||
|
||||
// Populate toy_list[].
|
||||
|
||||
#undef NEWTOY
|
||||
#undef OLDTOY
|
||||
#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags},
|
||||
#define OLDTOY(name, oldname, flags) \
|
||||
{#name, oldname##_main, OPTSTR_##oldname, flags},
|
||||
|
||||
struct toy_list toy_list[] = {
|
||||
#include "generated/newtoys.h"
|
||||
};
|
||||
|
||||
// global context for this command.
|
||||
|
||||
struct toy_context toys;
|
||||
union global_union this;
|
||||
char toybuf[4096], libbuf[4096];
|
||||
|
||||
struct toy_list *toy_find(char *name)
|
||||
{
|
||||
int top, bottom, middle;
|
||||
|
||||
if (!CFG_TOYBOX || strchr(name, '/')) return 0;
|
||||
|
||||
// If the name starts with "toybox" accept that as a match. Otherwise
|
||||
// skip the first entry, which is out of order.
|
||||
|
||||
if (!strncmp(name, "toybox", 6)) return toy_list;
|
||||
bottom = 1;
|
||||
|
||||
// Binary search to find this command.
|
||||
|
||||
top = ARRAY_LEN(toy_list)-1;
|
||||
for (;;) {
|
||||
int result;
|
||||
|
||||
middle = (top+bottom)/2;
|
||||
if (middle<bottom || middle>top) return 0;
|
||||
result = strcmp(name,toy_list[middle].name);
|
||||
if (!result) return toy_list+middle;
|
||||
if (result<0) top = --middle;
|
||||
else bottom = ++middle;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out whether or not anything is using the option parsing logic,
|
||||
// because the compiler can't figure out whether or not to optimize it away
|
||||
// on its' own. NEED_OPTIONS becomes a constant allowing if() to optimize
|
||||
// stuff out via dead code elimination.
|
||||
|
||||
#undef NEWTOY
|
||||
#undef OLDTOY
|
||||
#define NEWTOY(name, opts, flags) opts ||
|
||||
#define OLDTOY(name, oldname, flags) OPTSTR_##oldname ||
|
||||
static const int NEED_OPTIONS =
|
||||
#include "generated/newtoys.h"
|
||||
0; // Ends the opts || opts || opts...
|
||||
|
||||
static void unknown(char *name)
|
||||
{
|
||||
toys.exitval = 127;
|
||||
toys.which = toy_list;
|
||||
error_exit("Unknown command %s", name);
|
||||
}
|
||||
|
||||
// Setup toybox global state for this command.
|
||||
static void toy_singleinit(struct toy_list *which, char *argv[])
|
||||
{
|
||||
toys.which = which;
|
||||
toys.argv = argv;
|
||||
|
||||
if (CFG_TOYBOX_I18N) setlocale(LC_CTYPE, "C.UTF-8");
|
||||
setlinebuf(stdout);
|
||||
|
||||
// Parse --help and --version for (almost) all commands
|
||||
if (CFG_TOYBOX_HELP_DASHDASH && !(which->flags & TOYFLAG_NOHELP) && argv[1]) {
|
||||
if (!strcmp(argv[1], "--help")) {
|
||||
if (CFG_TOYBOX && toys.which == toy_list && toys.argv[2])
|
||||
if (!(toys.which = toy_find(toys.argv[2]))) unknown(toys.argv[2]);
|
||||
show_help(stdout);
|
||||
xexit();
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "--version")) {
|
||||
xputs("toybox "TOYBOX_VERSION);
|
||||
xexit();
|
||||
}
|
||||
}
|
||||
|
||||
if (NEED_OPTIONS && which->options) get_optflags();
|
||||
else {
|
||||
toys.optargs = argv+1;
|
||||
for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++);
|
||||
}
|
||||
toys.old_umask = umask(0);
|
||||
if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask);
|
||||
toys.signalfd--;
|
||||
toys.toycount = ARRAY_LEN(toy_list);
|
||||
}
|
||||
|
||||
// Full init needed by multiplexer or reentrant calls, calls singleinit at end
|
||||
void toy_init(struct toy_list *which, char *argv[])
|
||||
{
|
||||
void *oldwhich = toys.which;
|
||||
|
||||
// Drop permissions for non-suid commands.
|
||||
|
||||
if (CFG_TOYBOX_SUID) {
|
||||
if (!toys.which) toys.which = toy_list;
|
||||
|
||||
uid_t uid = getuid(), euid = geteuid();
|
||||
|
||||
if (!(which->flags & TOYFLAG_STAYROOT)) {
|
||||
if (uid != euid) {
|
||||
if (setuid(uid)) perror_exit("setuid %d->%d", euid, uid); // drop root
|
||||
euid = uid;
|
||||
toys.wasroot++;
|
||||
}
|
||||
} else if (CFG_TOYBOX_DEBUG && uid && which != toy_list)
|
||||
error_msg("Not installed suid root");
|
||||
|
||||
if ((which->flags & TOYFLAG_NEEDROOT) && euid) help_exit("Not root");
|
||||
}
|
||||
|
||||
// Free old toys contents (to be reentrant), but leave rebound if any
|
||||
// don't blank old optargs if our new argc lives in the old optargs.
|
||||
if (argv<toys.optargs || argv>toys.optargs+toys.optc) free(toys.optargs);
|
||||
memset(&toys, 0, offsetof(struct toy_context, rebound));
|
||||
if (oldwhich) memset(&this, 0, sizeof(this));
|
||||
|
||||
// Continue to portion of init needed by standalone commands
|
||||
toy_singleinit(which, argv);
|
||||
}
|
||||
|
||||
// Run an internal toybox command.
|
||||
// Only returns if it can't run command internally, otherwise xexit() when done.
|
||||
void toy_exec_which(struct toy_list *which, char *argv[])
|
||||
{
|
||||
// Return if we can't find it (which includes no multiplexer case),
|
||||
if (!which) return;
|
||||
|
||||
// Return if stack depth getting noticeable (proxy for leaked heap, etc).
|
||||
|
||||
// Compiler writers have decided subtracting char * is undefined behavior,
|
||||
// so convert to integers. (LP64 says sizeof(long)==sizeof(pointer).)
|
||||
// Signed typecast so stack growth direction is irrelevant: we're measuring
|
||||
// the distance between two pointers on the same stack, hence the labs().
|
||||
if (!CFG_TOYBOX_NORECURSE && toys.stacktop)
|
||||
if (labs((long)toys.stacktop-(long)&which)>6000) return;
|
||||
|
||||
// Return if we need to re-exec to acquire root via suid bit.
|
||||
if (toys.which && (which->flags&TOYFLAG_ROOTONLY) && toys.wasroot) return;
|
||||
|
||||
// Run command
|
||||
toy_init(which, argv);
|
||||
if (toys.which) toys.which->toy_main();
|
||||
xexit();
|
||||
}
|
||||
|
||||
// Lookup internal toybox command to run via argv[0]
|
||||
void toy_exec(char *argv[])
|
||||
{
|
||||
toy_exec_which(toy_find(basename(*argv)), argv);
|
||||
}
|
||||
|
||||
// Multiplexer command, first argument is command to run, rest are args to that.
|
||||
// If first argument starts with - output list of command install paths.
|
||||
void toybox_main(void)
|
||||
{
|
||||
static char *toy_paths[]={"usr/","bin/","sbin/",0};
|
||||
int i, len = 0;
|
||||
|
||||
// fast path: try to exec immediately.
|
||||
// (Leave toys.which null to disable suid return logic.)
|
||||
// Try dereferencing one layer of symlink
|
||||
if (toys.argv[1]) {
|
||||
toy_exec(toys.argv+1);
|
||||
if (0<readlink(toys.argv[1], libbuf, sizeof(libbuf))) {
|
||||
struct toy_list *tl= toy_find(basename(libbuf));
|
||||
|
||||
if (tl == toy_list) unknown(basename(toys.argv[1]));
|
||||
else toy_exec_which(tl, toys.argv+1);
|
||||
}
|
||||
}
|
||||
|
||||
// For early error reporting
|
||||
toys.which = toy_list;
|
||||
|
||||
if (toys.argv[1] && toys.argv[1][0] != '-') unknown(toys.argv[1]);
|
||||
|
||||
// Output list of command.
|
||||
for (i=1; i<ARRAY_LEN(toy_list); i++) {
|
||||
int fl = toy_list[i].flags;
|
||||
if (fl & TOYMASK_LOCATION) {
|
||||
if (toys.argv[1]) {
|
||||
int j;
|
||||
for (j=0; toy_paths[j]; j++)
|
||||
if (fl & (1<<j)) len += printf("%s", toy_paths[j]);
|
||||
}
|
||||
len += printf("%s",toy_list[i].name);
|
||||
if (++len > 65) len = 0;
|
||||
xputc(len ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
xputc('\n');
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (!*argv) return 127;
|
||||
|
||||
// Snapshot stack location so we can detect recursion depth later.
|
||||
// This is its own block so probe doesn't permanently consume stack.
|
||||
else {
|
||||
int stack;
|
||||
|
||||
toys.stacktop = &stack;
|
||||
}
|
||||
|
||||
// Up to and including Android M, bionic's dynamic linker added a handler to
|
||||
// cause a crash dump on SIGPIPE. That was removed in Android N, but adbd
|
||||
// was still setting the SIGPIPE disposition to SIG_IGN, and its children
|
||||
// were inheriting that. In Android O, adbd is fixed, but manually asking
|
||||
// for the default disposition is harmless, and it'll be a long time before
|
||||
// no one's using anything older than O!
|
||||
if (CFG_TOYBOX_ON_ANDROID) signal(SIGPIPE, SIG_DFL);
|
||||
|
||||
// If nommu can't fork, special reentry path.
|
||||
// Use !stacktop to signal "vfork happened", both before and after xexec()
|
||||
if (!CFG_TOYBOX_FORK) {
|
||||
if (0x80 & **argv) {
|
||||
**argv &= 0x7f;
|
||||
toys.stacktop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (CFG_TOYBOX) {
|
||||
// Call the multiplexer, adjusting this argv[] to be its' argv[1].
|
||||
// (It will adjust it back before calling toy_exec().)
|
||||
toys.argv = argv-1;
|
||||
toybox_main();
|
||||
} else {
|
||||
// a single toybox command built standalone with no multiplexer
|
||||
toy_singleinit(toy_list, argv);
|
||||
toy_list->toy_main();
|
||||
}
|
||||
|
||||
xexit();
|
||||
}
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
echo "usage: bloatcheck old new"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
addline()
|
||||
{
|
||||
NEXT="$(printf "%s% $((50-${#LASTNAME}))d% 10d %10d" "$LASTNAME" "$OLD" "$NEW" "$DELTA")"
|
||||
[ -z "$STUFF" ] &&
|
||||
STUFF="$NEXT" ||
|
||||
STUFF="$(printf "%s\n%s" "$STUFF" "$NEXT")"
|
||||
}
|
||||
|
||||
do_bloatcheck()
|
||||
{
|
||||
LASTNAME=
|
||||
DELTA=0
|
||||
TOTAL=0
|
||||
OLD=0
|
||||
NEW=0
|
||||
STUFF=
|
||||
|
||||
printf "name% 46s% 10s% 11s\n" old new delta
|
||||
echo "-----------------------------------------------------------------------"
|
||||
while read a b c d
|
||||
do
|
||||
THISNAME=$(echo "$d" | sed 's/[.][0-9]*$//')
|
||||
|
||||
if [ "$LASTNAME" != "$THISNAME" ]
|
||||
then
|
||||
TOTAL=$(($TOTAL+$DELTA))
|
||||
[ $DELTA -ne 0 ] && addline
|
||||
LASTNAME="$THISNAME"
|
||||
DELTA=0
|
||||
OLD=0
|
||||
NEW=0
|
||||
fi
|
||||
|
||||
SIZE=$(printf "%d" "0x$b")
|
||||
if [ "$a" == "-" ]
|
||||
then
|
||||
OLD=$(($OLD+$SIZE))
|
||||
SIZE=$((-1*$SIZE))
|
||||
else
|
||||
NEW=$(($NEW+$SIZE))
|
||||
fi
|
||||
DELTA=$(($DELTA+$SIZE))
|
||||
done
|
||||
|
||||
TOTAL=$(($TOTAL+$DELTA))
|
||||
[ $DELTA -ne 0 ] && addline
|
||||
|
||||
echo "$STUFF" | sort -k4,4nr
|
||||
echo "-----------------------------------------------------------------------"
|
||||
printf "% 71d total\n" "$TOTAL"
|
||||
}
|
||||
|
||||
DIFF1=`mktemp base.XXXXXXX`
|
||||
DIFF2=`mktemp bloat.XXXXXXX`
|
||||
trap "rm $DIFF1 $DIFF2" EXIT
|
||||
nm --size-sort "$1" | sort -k3,3 > $DIFF1
|
||||
nm --size-sort "$2" | sort -k3,3 > $DIFF2
|
||||
diff -U 0 $DIFF1 $DIFF2 | tail -n +3 | sed -n 's/^\([-+]\)/\1 /p' \
|
||||
| sort -k4,4 | do_bloatcheck
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# build each command as a standalone executable
|
||||
|
||||
NOBUILD=1 scripts/make.sh > /dev/null &&
|
||||
${HOSTCC:-cc} -I . scripts/install.c -o generated/instlist &&
|
||||
export PREFIX=${PREFIX:-change/} &&
|
||||
mkdir -p "$PREFIX" || exit 1
|
||||
|
||||
# Build all the commands standalone except:
|
||||
|
||||
# sh - shell builtins like "cd" and "exit" need the multiplexer
|
||||
# help - needs to know what other commands are enabled (use command --help)
|
||||
|
||||
for i in $(generated/instlist | egrep -vw "sh|help")
|
||||
do
|
||||
echo -n " $i" &&
|
||||
scripts/single.sh $i > /dev/null 2>$PREFIX/${i}.bad &&
|
||||
rm $PREFIX/${i}.bad || echo -n '*'
|
||||
done
|
||||
echo
|
||||
@@ -0,0 +1,523 @@
|
||||
/* config2.help.c - config2hep Config.in .config > help.h
|
||||
|
||||
function parse() reads Config.in data into *sym list, then
|
||||
we read .config and set sym->try on each enabled symbol.
|
||||
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <inttypes.h>
|
||||
#include <termios.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
//****************** functions copied from lib/*.c ********************
|
||||
|
||||
struct double_list {
|
||||
struct double_list *next, *prev;
|
||||
char *data;
|
||||
};
|
||||
|
||||
// Die unless we can allocate memory.
|
||||
void *xmalloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret) {
|
||||
fprintf(stderr, "xmalloc(%ld)", (long)size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Die unless we can allocate enough space to sprintf() into.
|
||||
char *xmprintf(char *format, ...)
|
||||
{
|
||||
va_list va, va2;
|
||||
int len;
|
||||
char *ret;
|
||||
|
||||
va_start(va, format);
|
||||
va_copy(va2, va);
|
||||
|
||||
// How long is it?
|
||||
len = vsnprintf(0, 0, format, va);
|
||||
len++;
|
||||
va_end(va);
|
||||
|
||||
// Allocate and do the sprintf()
|
||||
ret = xmalloc(len);
|
||||
vsnprintf(ret, len, format, va2);
|
||||
va_end(va2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Die unless we can open/create a file, returning FILE *.
|
||||
FILE *xfopen(char *path, char *mode)
|
||||
{
|
||||
FILE *f = fopen(path, mode);
|
||||
if (!f) {
|
||||
fprintf(stderr, "No file %s", path);
|
||||
exit(1);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void *dlist_pop(void *list)
|
||||
{
|
||||
struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist;
|
||||
|
||||
if (dlist->next == dlist) *pdlist = 0;
|
||||
else {
|
||||
dlist->next->prev = dlist->prev;
|
||||
dlist->prev->next = *pdlist = dlist->next;
|
||||
}
|
||||
|
||||
return dlist;
|
||||
}
|
||||
|
||||
void dlist_add_nomalloc(struct double_list **list, struct double_list *new)
|
||||
{
|
||||
if (*list) {
|
||||
new->next = *list;
|
||||
new->prev = (*list)->prev;
|
||||
(*list)->prev->next = new;
|
||||
(*list)->prev = new;
|
||||
} else *list = new->next = new->prev = new;
|
||||
}
|
||||
|
||||
|
||||
// Add an entry to the end of a doubly linked list
|
||||
struct double_list *dlist_add(struct double_list **list, char *data)
|
||||
{
|
||||
struct double_list *new = xmalloc(sizeof(struct double_list));
|
||||
|
||||
new->data = data;
|
||||
dlist_add_nomalloc(list, new);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
//****************** end copies of lib/*.c *************
|
||||
|
||||
// Parse config files into data structures.
|
||||
|
||||
struct symbol {
|
||||
struct symbol *next;
|
||||
int enabled, help_indent;
|
||||
char *name, *depends;
|
||||
struct double_list *help;
|
||||
} *sym;
|
||||
|
||||
// remove leading spaces
|
||||
char *skip_spaces(char *s)
|
||||
{
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// if line starts with name (as whole word) return pointer after it, else NULL
|
||||
char *keyword(char *name, char *line)
|
||||
{
|
||||
int len = strlen(name);
|
||||
|
||||
line = skip_spaces(line);
|
||||
if (strncmp(name, line, len)) return 0;
|
||||
line += len;
|
||||
if (*line && !isspace(*line)) return 0;
|
||||
line = skip_spaces(line);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
// dlist_pop() freeing wrapper structure for you.
|
||||
char *dlist_zap(struct double_list **help)
|
||||
{
|
||||
struct double_list *dd = dlist_pop(help);
|
||||
char *s = dd->data;
|
||||
|
||||
free(dd);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int zap_blank_lines(struct double_list **help)
|
||||
{
|
||||
int got = 0;
|
||||
|
||||
while (*help) {
|
||||
char *s;
|
||||
|
||||
s = skip_spaces((*help)->data);
|
||||
|
||||
if (*s) break;
|
||||
got++;
|
||||
free(dlist_zap(help));
|
||||
}
|
||||
|
||||
return got;
|
||||
}
|
||||
|
||||
// Collect "-a blah" description lines following a blank line (or start).
|
||||
// Returns array of removed lines with *len entries (0 for none).
|
||||
|
||||
// Moves *help to new start of text (in case dash lines were at beginning).
|
||||
// Sets *from to where dash lines removed from (in case they weren't).
|
||||
// Discards blank lines before and after dashlines.
|
||||
|
||||
// If no prefix, *help NULL. If no postfix, *from == *help
|
||||
// if no dashlines returned *from == *help.
|
||||
|
||||
char **grab_dashlines(struct double_list **help, struct double_list **from,
|
||||
int *len)
|
||||
{
|
||||
struct double_list *dd;
|
||||
char *s, **list;
|
||||
int count = 0;
|
||||
|
||||
*len = 0;
|
||||
zap_blank_lines(help);
|
||||
*from = *help;
|
||||
|
||||
// Find start of dash block. Must be at start or after blank line.
|
||||
for (;;) {
|
||||
s = skip_spaces((*from)->data);
|
||||
if (*s == '-' && s[1] != '-' && !count) break;
|
||||
|
||||
if (!*s) count = 0;
|
||||
else count++;
|
||||
|
||||
*from = (*from)->next;
|
||||
if (*from == *help) return 0;
|
||||
}
|
||||
|
||||
// If there was whitespace before this, zap it. This can't take out *help
|
||||
// because zap_blank_lines skipped blank lines, and we had to have at least
|
||||
// one non-blank line (a dash line) to get this far.
|
||||
while (!*skip_spaces((*from)->prev->data)) {
|
||||
*from = (*from)->prev;
|
||||
free(dlist_zap(from));
|
||||
}
|
||||
|
||||
// Count number of dashlines, copy out to array, zap trailing whitespace
|
||||
// If *help was at start of dashblock, move it with *from
|
||||
count = 0;
|
||||
dd = *from;
|
||||
if (*help == *from) *help = 0;
|
||||
for (;;) {
|
||||
if (*skip_spaces(dd->data) != '-') break;
|
||||
count++;
|
||||
if (*from == (dd = dd->next)) break;
|
||||
}
|
||||
|
||||
list = xmalloc(sizeof(char *)*count);
|
||||
*len = count;
|
||||
while (count) list[--count] = dlist_zap(from);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Read Config.in (and includes) to populate global struct symbol *sym list.
|
||||
void parse(char *filename)
|
||||
{
|
||||
FILE *fp = xfopen(filename, "r");
|
||||
struct symbol *new = 0;
|
||||
|
||||
for (;;) {
|
||||
char *s, *line = NULL;
|
||||
size_t len;
|
||||
|
||||
// Read line, trim whitespace at right edge.
|
||||
if (getline(&line, &len, fp) < 1) break;
|
||||
s = line+strlen(line);
|
||||
while (--s >= line) {
|
||||
if (!isspace(*s)) break;
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
// source or config keyword at left edge?
|
||||
if (*line && !isspace(*line)) {
|
||||
if ((s = keyword("config", line))) {
|
||||
memset(new = xmalloc(sizeof(struct symbol)), 0, sizeof(struct symbol));
|
||||
new->next = sym;
|
||||
new->name = s;
|
||||
sym = new;
|
||||
} else if ((s = keyword("source", line))) parse(s);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!new) continue;
|
||||
|
||||
if (sym && sym->help_indent) {
|
||||
dlist_add(&(new->help), line);
|
||||
if (sym->help_indent < 0) {
|
||||
sym->help_indent = 0;
|
||||
while (isspace(line[sym->help_indent])) sym->help_indent++;
|
||||
}
|
||||
}
|
||||
else if ((s = keyword("depends", line)) && (s = keyword("on", s)))
|
||||
new->depends = s;
|
||||
else if (keyword("help", line)) sym->help_indent = -1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int charsort(void *a, void *b)
|
||||
{
|
||||
char *aa = a, *bb = b;
|
||||
|
||||
if (*aa < *bb) return -1;
|
||||
if (*aa > *bb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dashsort(char **a, char **b)
|
||||
{
|
||||
char *aa = *a, *bb = *b;
|
||||
|
||||
if (aa[1] < bb[1]) return -1;
|
||||
if (aa[1] > bb[1]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dashlinesort(char **a, char **b)
|
||||
{
|
||||
return strcmp(*a, *b);
|
||||
}
|
||||
|
||||
// Three stages: read data, collate entries, output results.
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: config2help Config.in .config\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Stage 1: read data. Read Config.in to global 'struct symbol *sym' list,
|
||||
// then read .config to set "enabled" member of each enabled symbol.
|
||||
|
||||
// Read Config.in
|
||||
parse(argv[1]);
|
||||
|
||||
// read .config
|
||||
fp = xfopen(argv[2], "r");
|
||||
for (;;) {
|
||||
char *line = NULL;
|
||||
size_t len;
|
||||
|
||||
if (getline(&line, &len, fp) < 1) break;
|
||||
if (!strncmp("CONFIG_", line, 7)) {
|
||||
struct symbol *try;
|
||||
char *s = line+7;
|
||||
|
||||
for (try=sym; try; try=try->next) {
|
||||
len = strlen(try->name);
|
||||
if (!strncmp(try->name, s, len) && s[len]=='=' && s[len+1]=='y') {
|
||||
try->enabled++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stage 2: process data.
|
||||
|
||||
// Collate help according to usage, depends, and .config
|
||||
|
||||
// Loop through each entry, finding duplicate enabled "usage:" names
|
||||
// This is in reverse order, so last entry gets collated with previous
|
||||
// entry until we run out of matching pairs.
|
||||
for (;;) {
|
||||
struct symbol *throw = 0, *catch;
|
||||
char *this, *that, *cusage, *tusage, *name = 0;
|
||||
int len;
|
||||
|
||||
// find a usage: name and collate all enabled entries with that name
|
||||
for (catch = sym; catch; catch = catch->next) {
|
||||
if (catch->enabled != 1) continue;
|
||||
if (catch->help && (that = keyword("usage:", catch->help->data))) {
|
||||
struct double_list *cfrom, *tfrom, *anchor;
|
||||
char *try, **cdashlines, **tdashlines, *usage;
|
||||
int clen, tlen;
|
||||
|
||||
// Align usage: lines, finding a matching pair so we can suck help
|
||||
// text out of throw into catch, copying from this to that
|
||||
if (!throw) usage = that;
|
||||
else if (strncmp(name, that, len) || !isspace(that[len])) continue;
|
||||
catch->enabled++;
|
||||
while (!isspace(*that) && *that) that++;
|
||||
if (!throw) len = that-usage;
|
||||
free(name);
|
||||
name = strndup(usage, len);
|
||||
that = skip_spaces(that);
|
||||
if (!throw) {
|
||||
throw = catch;
|
||||
this = that;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab option description lines to collate from catch and throw
|
||||
tusage = dlist_zap(&throw->help);
|
||||
tdashlines = grab_dashlines(&throw->help, &tfrom, &tlen);
|
||||
cusage = dlist_zap(&catch->help);
|
||||
cdashlines = grab_dashlines(&catch->help, &cfrom, &clen);
|
||||
anchor = catch->help;
|
||||
|
||||
// If we've got both, collate and alphebetize
|
||||
if (cdashlines && tdashlines) {
|
||||
char **new = xmalloc(sizeof(char *)*(clen+tlen));
|
||||
|
||||
memcpy(new, cdashlines, sizeof(char *)*clen);
|
||||
memcpy(new+clen, tdashlines, sizeof(char *)*tlen);
|
||||
free(cdashlines);
|
||||
free(tdashlines);
|
||||
qsort(new, clen+tlen, sizeof(char *), (void *)dashlinesort);
|
||||
cdashlines = new;
|
||||
|
||||
// If just one, make sure it's in catch.
|
||||
} else if (tdashlines) cdashlines = tdashlines;
|
||||
|
||||
// If throw had a prefix, insert it before dashlines, with a
|
||||
// blank line if catch had a prefix.
|
||||
if (tfrom && tfrom != throw->help) {
|
||||
if (throw->help || catch->help) dlist_add(&cfrom, strdup(""));
|
||||
else {
|
||||
dlist_add(&cfrom, 0);
|
||||
anchor = cfrom->prev;
|
||||
}
|
||||
while (throw->help && throw->help != tfrom)
|
||||
dlist_add(&cfrom, dlist_zap(&throw->help));
|
||||
if (cfrom && cfrom->prev->data && *skip_spaces(cfrom->prev->data))
|
||||
dlist_add(&cfrom, strdup(""));
|
||||
}
|
||||
if (!anchor) {
|
||||
dlist_add(&cfrom, 0);
|
||||
anchor = cfrom->prev;
|
||||
}
|
||||
|
||||
// Splice sorted lines back in place
|
||||
if (cdashlines) {
|
||||
tlen += clen;
|
||||
|
||||
for (clen = 0; clen < tlen; clen++)
|
||||
dlist_add(&cfrom, cdashlines[clen]);
|
||||
}
|
||||
|
||||
// If there were no dashlines, text would be considered prefix, so
|
||||
// the list is definitely no longer empty, so discard placeholder.
|
||||
if (!anchor->data) dlist_zap(&anchor);
|
||||
|
||||
// zap whitespace at end of catch help text
|
||||
while (!*skip_spaces(anchor->prev->data)) {
|
||||
anchor = anchor->prev;
|
||||
free(dlist_zap(&anchor));
|
||||
}
|
||||
|
||||
// Append trailing lines.
|
||||
while (tfrom) dlist_add(&anchor, dlist_zap(&tfrom));
|
||||
|
||||
// Collate first [-abc] option block in usage: lines
|
||||
try = 0;
|
||||
if (*this == '[' && this[1] == '-' && this[2] != '-' &&
|
||||
*that == '[' && that[1] == '-' && that[2] != '-')
|
||||
{
|
||||
char *from = this+2, *to = that+2;
|
||||
int ff = strcspn(from, " ]"), tt = strcspn(to, " ]");
|
||||
|
||||
if (from[ff] == ']' && to[tt] == ']') {
|
||||
try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to);
|
||||
qsort(try+2, ff+tt, 1, (void *)charsort);
|
||||
this = skip_spaces(this+ff+3);
|
||||
that = skip_spaces(that+tt+3);
|
||||
}
|
||||
}
|
||||
|
||||
// The list is definitely no longer empty, so discard placeholder.
|
||||
if (!anchor->data) dlist_zap(&anchor);
|
||||
|
||||
// Add new collated line (and whitespace).
|
||||
dlist_add(&anchor, xmprintf("%*cusage: %.*s %s%s%s%s",
|
||||
catch->help_indent, ' ', len, name, try ? try : "",
|
||||
this, *this ? " " : "", that));
|
||||
free(try);
|
||||
dlist_add(&anchor, strdup(""));
|
||||
free(cusage);
|
||||
free(tusage);
|
||||
throw->enabled = 0;
|
||||
throw = catch;
|
||||
throw->help = anchor->prev->prev;
|
||||
|
||||
throw = catch;
|
||||
this = throw->help->data + throw->help_indent + 8 + len;
|
||||
}
|
||||
}
|
||||
|
||||
// Did we find one?
|
||||
|
||||
if (!throw) break;
|
||||
}
|
||||
|
||||
// Stage 3: output results to stdout.
|
||||
|
||||
// Print out help #defines
|
||||
while (sym) {
|
||||
struct double_list *dd;
|
||||
|
||||
if (sym->help) {
|
||||
int i, blank;
|
||||
char *s;
|
||||
|
||||
strcpy(s = xmalloc(strlen(sym->name)+1), sym->name);
|
||||
|
||||
for (i = 0; s[i]; i++) s[i] = tolower(s[i]);
|
||||
printf("#define HELP_%s \"", s);
|
||||
free(s);
|
||||
|
||||
dd = sym->help;
|
||||
blank = 0;
|
||||
for (;;) {
|
||||
|
||||
// Trim leading whitespace
|
||||
s = dd->data;
|
||||
i = sym->help_indent;
|
||||
while (isspace(*s) && i--) s++;
|
||||
|
||||
// Only one blank line between nonblank lines, not at start or end.
|
||||
if (!*s) blank = 2;
|
||||
else {
|
||||
while (blank--) {
|
||||
putchar('\\');
|
||||
putchar('n');
|
||||
}
|
||||
blank = 1;
|
||||
}
|
||||
|
||||
for (i=0; s[i]; i++) {
|
||||
if (s[i] == '"' || s[i] == '\\') putchar('\\');
|
||||
putchar(s[i]);
|
||||
}
|
||||
dd = dd->next;
|
||||
if (dd == sym->help) break;
|
||||
}
|
||||
printf("\"\n\n");
|
||||
}
|
||||
sym = sym->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Convenience wrapper to set $CROSS_COMPILE from short name using "ccc"
|
||||
# symlink (Cross C Compiler) to a directory of cross compilers named
|
||||
# $TARGET-*-cross. Tested with scripts/mcm-buildall.sh output.
|
||||
|
||||
# Usage: scripts/cross.sh $TARGET make distclean defconfig toybox
|
||||
# With no arguments, lists available targets. Use target "all" to iterate
|
||||
# through each $TARGET from the list.
|
||||
|
||||
CCC="$(dirname "$(readlink -f "$0")")"/../ccc
|
||||
if [ ! -d "$CCC" ]
|
||||
then
|
||||
echo "Create symlink 'ccc' to cross compiler directory, ala:"
|
||||
echo " ln -s ~/musl-cross-make/ccc ccc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unset X Y
|
||||
|
||||
# Display target list?
|
||||
list()
|
||||
{
|
||||
ls "$CCC" | sed 's/-.*//' | sort -u | xargs
|
||||
}
|
||||
[ $# -eq 0 ] && list && exit
|
||||
|
||||
X="$1"
|
||||
shift
|
||||
|
||||
# build all targets?
|
||||
if [ "$X" == all ]
|
||||
then
|
||||
for TARGET in $(list)
|
||||
do
|
||||
{
|
||||
export TARGET
|
||||
"$0" $TARGET "$@" 2>&1 || mv cross-log-$TARGET.{txt,failed}
|
||||
} | tee cross-log-$TARGET.txt
|
||||
done
|
||||
|
||||
exit
|
||||
fi
|
||||
|
||||
# Call command with CROSS_COMPILE= as its first argument
|
||||
|
||||
Y=$(echo "$CCC/$X"-*cross)
|
||||
Z=$(basename "$Y")
|
||||
Y=$(readlink -f "$CCC"/$X-*cross)
|
||||
export TARGET="${Z/-*/}"
|
||||
X="$Y/bin/${Z/-cross/-}"
|
||||
[ ! -e "${X}cc" ] && echo "${X}cc not found" && exit 1
|
||||
|
||||
CROSS_COMPILE="$X" "$@"
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Quick and dirty check to see if anybody's leaked global variables.
|
||||
# We should have this, toy_list, toybuf, and toys.
|
||||
|
||||
nm toybox_unstripped | grep '[0-9A-Fa-f]* [BCDGRS]' | cut -d ' ' -f 3
|
||||
Executable
+169
@@ -0,0 +1,169 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This has to be a separate file from scripts/make.sh so it can be called
|
||||
# before menuconfig. (It's called again from scripts/make.sh just to be sure.)
|
||||
|
||||
mkdir -p generated
|
||||
|
||||
source scripts/portability.sh
|
||||
|
||||
probecc()
|
||||
{
|
||||
${CROSS_COMPILE}${CC} $CFLAGS -xc -o /dev/null $1 -
|
||||
}
|
||||
|
||||
# Probe for a single config symbol with a "compiles or not" test.
|
||||
# Symbol name is first argument, flags second, feed C file to stdin
|
||||
probesymbol()
|
||||
{
|
||||
probecc $2 2>/dev/null && DEFAULT=y || DEFAULT=n
|
||||
rm a.out 2>/dev/null
|
||||
echo -e "config $1\n\tbool" || exit 1
|
||||
echo -e "\tdefault $DEFAULT\n" || exit 1
|
||||
}
|
||||
|
||||
probeconfig()
|
||||
{
|
||||
> generated/cflags
|
||||
# llvm produces its own really stupid warnings about things that aren't wrong,
|
||||
# and although you can turn the warning off, gcc reacts badly to command line
|
||||
# arguments it doesn't understand. So probe.
|
||||
[ -z "$(probecc -Wno-string-plus-int <<< \#warn warn 2>&1 | grep string-plus-int)" ] &&
|
||||
echo -Wno-string-plus-int >> generated/cflags
|
||||
|
||||
# Probe for container support on target
|
||||
probesymbol TOYBOX_CONTAINER << EOF
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/sched.h>
|
||||
int x=CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET;
|
||||
|
||||
int main(int argc, char *argv[]){printf("%d", x+SYS_unshare+ SYS_setns);}
|
||||
EOF
|
||||
|
||||
probesymbol TOYBOX_FIFREEZE -c << EOF
|
||||
#include <linux/fs.h>
|
||||
#ifndef FIFREEZE
|
||||
#error nope
|
||||
#endif
|
||||
EOF
|
||||
|
||||
# Work around some uClibc limitations
|
||||
probesymbol TOYBOX_ICONV -c << EOF
|
||||
#include "iconv.h"
|
||||
EOF
|
||||
probesymbol TOYBOX_FALLOCATE << EOF
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(int argc, char *argv[]) { return posix_fallocate(0,0,0); }
|
||||
EOF
|
||||
|
||||
# Android and some other platforms miss utmpx
|
||||
probesymbol TOYBOX_UTMPX -c << EOF
|
||||
#include <utmpx.h>
|
||||
#ifndef BOOT_TIME
|
||||
#error nope
|
||||
#endif
|
||||
int main(int argc, char *argv[]) {
|
||||
struct utmpx *a;
|
||||
if (0 != (a = getutxent())) return 0;
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Android is missing shadow.h
|
||||
probesymbol TOYBOX_SHADOW -c << EOF
|
||||
#include <shadow.h>
|
||||
int main(int argc, char *argv[]) {
|
||||
struct spwd *a = getspnam("root"); return 0;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Some commands are android-specific
|
||||
probesymbol TOYBOX_ON_ANDROID -c << EOF
|
||||
#ifndef __ANDROID__
|
||||
#error nope
|
||||
#endif
|
||||
EOF
|
||||
|
||||
probesymbol TOYBOX_ANDROID_SCHEDPOLICY << EOF
|
||||
#include <processgroup/sched_policy.h>
|
||||
|
||||
int main(int argc,char *argv[]) { get_sched_policy_name(0); }
|
||||
EOF
|
||||
|
||||
# nommu support
|
||||
probesymbol TOYBOX_FORK << EOF
|
||||
#include <unistd.h>
|
||||
int main(int argc, char *argv[]) { return fork(); }
|
||||
EOF
|
||||
echo -e '\tdepends on !TOYBOX_MUSL_NOMMU_IS_BROKEN'
|
||||
|
||||
probesymbol TOYBOX_PRLIMIT << EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
|
||||
struct rlimit *old_limit);
|
||||
int main(int argc, char *argv[]) { prlimit(0, 0, 0, 0); }
|
||||
EOF
|
||||
|
||||
probesymbol TOYBOX_GETRANDOM << EOF
|
||||
#include <sys/random.h>
|
||||
int main(void) { char buf[100]; getrandom(buf, 100, 0); }
|
||||
EOF
|
||||
}
|
||||
|
||||
genconfig()
|
||||
{
|
||||
# Reverse sort puts posix first, examples last.
|
||||
for j in $(ls toys/*/README | sort -s -r)
|
||||
do
|
||||
DIR="$(dirname "$j")"
|
||||
|
||||
[ $(ls "$DIR" | wc -l) -lt 2 ] && continue
|
||||
|
||||
echo "menu \"$(head -n 1 $j)\""
|
||||
echo
|
||||
|
||||
# extract config stanzas from each source file, in alphabetical order
|
||||
for i in $(ls -1 $DIR/*.c)
|
||||
do
|
||||
# Grab the config block for Config.in
|
||||
echo "# $i"
|
||||
$SED -n '/^\*\//q;/^config [A-Z]/,$p' $i || return 1
|
||||
echo
|
||||
done
|
||||
|
||||
echo endmenu
|
||||
done
|
||||
}
|
||||
|
||||
probeconfig > generated/Config.probed || rm generated/Config.probed
|
||||
genconfig > generated/Config.in || rm generated/Config.in
|
||||
|
||||
# Find names of commands that can be built standalone in these C files
|
||||
toys()
|
||||
{
|
||||
grep 'TOY(.*)' "$@" | grep -v TOYFLAG_NOFORK | grep -v "0))" | \
|
||||
$SED -En 's/([^:]*):.*(OLD|NEW)TOY\( *([a-zA-Z][^,]*) *,.*/\1:\3/p'
|
||||
}
|
||||
|
||||
WORKING=
|
||||
PENDING=
|
||||
toys toys/*/*.c | (
|
||||
while IFS=":" read FILE NAME
|
||||
do
|
||||
[ "$NAME" == help ] && continue
|
||||
[ "$NAME" == install ] && continue
|
||||
echo -e "$NAME: $FILE *.[ch] lib/*.[ch]\n\tscripts/single.sh $NAME\n"
|
||||
echo -e "test_$NAME:\n\tscripts/test.sh $NAME\n"
|
||||
[ "${FILE/pending//}" != "$FILE" ] &&
|
||||
PENDING="$PENDING $NAME" ||
|
||||
WORKING="$WORKING $NAME"
|
||||
done &&
|
||||
echo -e "clean::\n\t@rm -f $WORKING $PENDING" &&
|
||||
echo -e "list:\n\t@echo $(echo $WORKING | tr ' ' '\n' | sort | xargs)" &&
|
||||
echo -e "list_pending:\n\t@echo $(echo $PENDING | tr ' ' '\n' | sort | xargs)" &&
|
||||
echo -e ".PHONY: $WORKING $PENDING" | $SED 's/ \([^ ]\)/ test_\1/g'
|
||||
) > .singlemake
|
||||
@@ -0,0 +1,22 @@
|
||||
toybox - Build toybox.
|
||||
COMMANDNAME - Build individual toybox command as a standalone binary.
|
||||
list - List COMMANDNAMEs you can build standalone.
|
||||
list_pending - List unfinished COMMANDNAMEs out of toys/pending.
|
||||
change - Build each command standalone under change/.
|
||||
baseline - Create toybox_old for use by bloatcheck.
|
||||
bloatcheck - Report size differences between old and current versions
|
||||
test_COMMAND - Run tests for COMMAND (test_ps, test_cat, etc.)
|
||||
tests - Run test suite against all compiled commands.
|
||||
export TEST_HOST=1 to test host command, VERBOSE=1
|
||||
to show diff, VERBOSE=fail to stop after first failure.
|
||||
clean - Delete temporary files.
|
||||
distclean - Delete everything that isn't shipped.
|
||||
install_airlock - Install toybox and host toolchain into $PREFIX directory
|
||||
(providing $PATH for hermetic builds).
|
||||
install_flat - Install toybox into $PREFIX directory.
|
||||
install - Install toybox into subdirectories of $PREFIX.
|
||||
uninstall_flat - Remove toybox from $PREFIX directory.
|
||||
uninstall - Remove toybox from subdirectories of $PREFIX.
|
||||
|
||||
example: CFLAGS="--static" CROSS_COMPILE=armv5l- make defconfig toybox install
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Wrapper to make installation easier with cross-compiling.
|
||||
*
|
||||
* Copyright 2006 Rob Landley <rob@landley.net>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "generated/config.h"
|
||||
#include "lib/toyflags.h"
|
||||
|
||||
#define NEWTOY(name, opts, flags) {#name, flags},
|
||||
#define OLDTOY(name, oldname, flags) {#name, flags},
|
||||
|
||||
// Populate toy_list[].
|
||||
|
||||
struct {char *name; int flags;} toy_list[] = {
|
||||
#include "generated/newtoys.h"
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static char *toy_paths[]={"usr/","bin/","sbin/",0};
|
||||
int i, len = 0;
|
||||
|
||||
// Output list of applets.
|
||||
for (i=1; i<sizeof(toy_list)/sizeof(*toy_list); i++) {
|
||||
int fl = toy_list[i].flags;
|
||||
if (fl & TOYMASK_LOCATION) {
|
||||
if (argc>1) {
|
||||
int j;
|
||||
for (j=0; toy_paths[j]; j++)
|
||||
if (fl & (1<<j)) len += printf("%s", toy_paths[j]);
|
||||
}
|
||||
len += printf("%s\n",toy_list[i].name);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Executable
+152
@@ -0,0 +1,152 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Grab default values for $CFLAGS and such.
|
||||
|
||||
source ./configure
|
||||
|
||||
[ -z "$PREFIX" ] && PREFIX="/usr/toybox"
|
||||
|
||||
# Parse command line arguments.
|
||||
|
||||
LONG_PATH=""
|
||||
while [ ! -z "$1" ]
|
||||
do
|
||||
# Create symlinks instead of hardlinks?
|
||||
[ "$1" == "--symlink" ] && LINK_TYPE="-s"
|
||||
|
||||
# Uninstall?
|
||||
[ "$1" == "--uninstall" ] && UNINSTALL=Uninstall
|
||||
|
||||
# Delete destination command if it exists?
|
||||
[ "$1" == "--force" ] && DO_FORCE="-f"
|
||||
|
||||
# Use {,usr}/{bin,sbin} paths instead of all files in one directory?
|
||||
[ "$1" == "--long" ] && LONG_PATH="bin/"
|
||||
|
||||
# Symlink host toolchain binaries to destination to create cross compile $PATH
|
||||
[ "$1" == "--airlock" ] && AIRLOCK=1
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
echo "Compile instlist..."
|
||||
|
||||
NOBUILD=1 scripts/make.sh
|
||||
$DEBUG $HOSTCC -I . scripts/install.c -o generated/instlist || exit 1
|
||||
COMMANDS="$(generated/instlist $LONG_PATH)"
|
||||
|
||||
echo "${UNINSTALL:-Install} commands..."
|
||||
|
||||
# Copy toybox itself
|
||||
|
||||
if [ -z "$UNINSTALL" ]
|
||||
then
|
||||
mkdir -p "${PREFIX}/${LONG_PATH}" &&
|
||||
rm -f "${PREFIX}/${LONG_PATH}/toybox" &&
|
||||
cp toybox ${PREFIX}/${LONG_PATH} || exit 1
|
||||
else
|
||||
rm -f "${PREFIX}/${LONG_PATH}/toybox" 2>/dev/null
|
||||
fi
|
||||
cd "$PREFIX" || exit 1
|
||||
|
||||
# Make links to toybox
|
||||
|
||||
EXIT=0
|
||||
|
||||
for i in $COMMANDS
|
||||
do
|
||||
# Figure out target of link
|
||||
|
||||
if [ -z "$LONG_PATH" ]
|
||||
then
|
||||
DOTPATH=""
|
||||
else
|
||||
# Create subdirectory for command to go in (if necessary)
|
||||
|
||||
DOTPATH="$(dirname "$i")"/
|
||||
if [ -z "$UNINSTALL" ]
|
||||
then
|
||||
mkdir -p "$DOTPATH" || exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$LINK_TYPE" ]
|
||||
then
|
||||
DOTPATH="bin/"
|
||||
else
|
||||
if [ "$DOTPATH" != "$LONG_PATH" ]
|
||||
then
|
||||
# For symlinks we need ../../bin style relative paths
|
||||
DOTPATH="$(echo $DOTPATH | sed -e 's@[^/]*/@../@g')"$LONG_PATH
|
||||
else
|
||||
DOTPATH=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create link
|
||||
if [ -z "$UNINSTALL" ]
|
||||
then
|
||||
ln $DO_FORCE $LINK_TYPE ${DOTPATH}toybox $i || EXIT=1
|
||||
else
|
||||
rm -f $i || EXIT=1
|
||||
fi
|
||||
done
|
||||
|
||||
[ -z "$AIRLOCK" ] && exit 0
|
||||
|
||||
# --airlock creates a single directory you can point the $PATH to for cross
|
||||
# compiling, which contains just toybox and symlinks to toolchain binaries.
|
||||
|
||||
# This not only means you're building with a known set of tools (insulated from
|
||||
# variations in the host distro), but that everything else is NOT in your PATH
|
||||
# and thus various configure stages won't find things on thie host that won't
|
||||
# be there on the target (such as the distcc build noticing the host has
|
||||
# python and deciding to #include Python.h).
|
||||
|
||||
# The following are commands toybox should provide, but doesn't yet.
|
||||
# For now symlink the host version. This list must go away by 1.0.
|
||||
|
||||
PENDING="dd diff expr ftpd less tr vi wget awk sh sha512sum sha256sum unxz xzcat bc bison flex make nm ar gzip"
|
||||
|
||||
# "gcc" should go away for llvm, but some things still hardwire it
|
||||
TOOLCHAIN="as cc ld gcc objdump"
|
||||
|
||||
if [ ! -z "$AIRLOCK" ]
|
||||
then
|
||||
|
||||
# Tools needed to build packages
|
||||
for i in $TOOLCHAIN $PENDING $HOST_EXTRA
|
||||
do
|
||||
if [ ! -f "$i" ]
|
||||
then
|
||||
# Loop through each instance, populating fallback directories (used by
|
||||
# things like distcc, which require multiple instances of the same binary
|
||||
# in a known order in the $PATH).
|
||||
|
||||
X=0
|
||||
FALLBACK="$PREFIX"
|
||||
which -a "$i" | while read j
|
||||
do
|
||||
if [ ! -e "$FALLBACK/$i" ]
|
||||
then
|
||||
mkdir -p "$FALLBACK" &&
|
||||
ln -sf "$j" "$FALLBACK/$i" || exit 1
|
||||
fi
|
||||
|
||||
X=$[$X+1]
|
||||
FALLBACK="$PREFIX/fallback-$X"
|
||||
done
|
||||
|
||||
if [ ! -f "$PREFIX/$i" ]
|
||||
then
|
||||
echo "Toolchain component missing: $i" >&2
|
||||
[ -z "$PEDANTIC" ] || EXIT=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
|
||||
fi
|
||||
|
||||
exit $EXIT
|
||||
Executable
+354
@@ -0,0 +1,354 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Grab default values for $CFLAGS and such.
|
||||
|
||||
if [ ! -z "$ASAN" ]; then
|
||||
# Turn ASan on.
|
||||
CFLAGS="-fsanitize=address $CFLAGS"
|
||||
# Optional, but effectively necessary if you want useful backtraces.
|
||||
CFLAGS="-O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls $CFLAGS"
|
||||
fi
|
||||
|
||||
export LANG=c
|
||||
export LC_ALL=C
|
||||
set -o pipefail
|
||||
source scripts/portability.sh
|
||||
|
||||
[ -z "$KCONFIG_CONFIG" ] && KCONFIG_CONFIG=.config
|
||||
[ -z "$OUTNAME" ] && OUTNAME=toybox"${TARGET:+-$TARGET}"
|
||||
UNSTRIPPED="generated/unstripped/$(basename "$OUTNAME")"
|
||||
|
||||
# Try to keep one more cc invocation going than we have processors
|
||||
[ -z "$CPUS" ] && \
|
||||
CPUS=$(($(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null)+1))
|
||||
|
||||
# Respond to V= by echoing command lines as well as running them
|
||||
DOTPROG=
|
||||
do_loudly()
|
||||
{
|
||||
[ ! -z "$V" ] && echo "$@" || echo -n "$DOTPROG"
|
||||
"$@"
|
||||
}
|
||||
|
||||
# Is anything under directory $2 newer than file $1
|
||||
isnewer()
|
||||
{
|
||||
CHECK="$1"
|
||||
shift
|
||||
[ ! -z "$(find "$@" -newer "$CHECK" 2>/dev/null || echo yes)" ]
|
||||
}
|
||||
|
||||
echo "Generate headers from toys/*/*.c..."
|
||||
|
||||
mkdir -p generated/unstripped
|
||||
|
||||
if isnewer generated/Config.in toys
|
||||
then
|
||||
echo "Extract configuration information from toys/*.c files..."
|
||||
scripts/genconfig.sh
|
||||
fi
|
||||
|
||||
# Create a list of all the commands toybox can provide. Note that the first
|
||||
# entry is out of order on purpose (the toybox multiplexer command must be the
|
||||
# first element of the array). The rest must be sorted in alphabetical order
|
||||
# for fast binary search.
|
||||
|
||||
if isnewer generated/newtoys.h toys
|
||||
then
|
||||
echo -n "generated/newtoys.h "
|
||||
|
||||
echo "USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))" > generated/newtoys.h
|
||||
$SED -n -e 's/^USE_[A-Z0-9_]*(/&/p' toys/*/*.c \
|
||||
| $SED 's/\(.*TOY(\)\([^,]*\),\(.*\)/\2 \1\2,\3/' | sort -s -k 1,1 \
|
||||
| $SED 's/[^ ]* //' >> generated/newtoys.h
|
||||
[ $? -ne 0 ] && exit 1
|
||||
fi
|
||||
|
||||
[ ! -z "$V" ] && echo "Which C files to build..."
|
||||
|
||||
# Extract a list of toys/*/*.c files to compile from the data in $KCONFIG_CONFIG
|
||||
# (First command names, then filenames with relevant {NEW,OLD}TOY() macro.)
|
||||
|
||||
[ -d ".git" ] && GITHASH="$(git describe --tags --abbrev=12 2>/dev/null)"
|
||||
[ ! -z "$GITHASH" ] && GITHASH="-DTOYBOX_VERSION=\"$GITHASH\""
|
||||
TOYFILES="$($SED -n 's/^CONFIG_\([^=]*\)=.*/\1/p' "$KCONFIG_CONFIG" | xargs | tr ' [A-Z]' '|[a-z]')"
|
||||
TOYFILES="$(egrep -l "TOY[(]($TOYFILES)[ ,]" toys/*/*.c)"
|
||||
CFLAGS="$CFLAGS $(cat generated/cflags)"
|
||||
BUILD="$(echo ${CROSS_COMPILE}${CC} $CFLAGS -I . $OPTIMIZE $GITHASH)"
|
||||
LIBFILES="$(ls lib/*.c | grep -v lib/help.c)"
|
||||
TOYFILES="lib/help.c main.c $TOYFILES"
|
||||
|
||||
if [ "${TOYFILES/pending//}" != "$TOYFILES" ]
|
||||
then
|
||||
echo -e "\n\033[1;31mwarning: using unfinished code from toys/pending\033[0m"
|
||||
fi
|
||||
|
||||
genbuildsh()
|
||||
{
|
||||
# Write a canned build line for use on crippled build machines.
|
||||
|
||||
echo "#!/bin/sh"
|
||||
echo
|
||||
echo "PATH='$PATH'"
|
||||
echo
|
||||
echo "BUILD='$BUILD'"
|
||||
echo
|
||||
echo "LINK='$LINK'"
|
||||
echo
|
||||
echo "FILES='$LIBFILES $TOYFILES'"
|
||||
echo
|
||||
echo
|
||||
echo '$BUILD $FILES $LINK'
|
||||
}
|
||||
|
||||
if ! cmp -s <(genbuildsh 2>/dev/null | head -n 6 ; echo LINK="'"$LDOPTIMIZE $LDFLAGS) \
|
||||
<(head -n 7 generated/build.sh 2>/dev/null | $SED '7s/ -o .*//')
|
||||
then
|
||||
echo -n "Library probe"
|
||||
|
||||
# We trust --as-needed to remove each library if we don't use any symbols
|
||||
# out of it, this loop is because the compiler has no way to ignore a library
|
||||
# that doesn't exist, so we have to detect and skip nonexistent libraries
|
||||
# for it.
|
||||
|
||||
> generated/optlibs.dat
|
||||
for i in util crypt m resolv selinux smack attr crypto z log iconv
|
||||
do
|
||||
echo "int main(int argc, char *argv[]) {return 0;}" | \
|
||||
${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc - -o generated/libprobe $LDASNEEDED -l$i > /dev/null 2>/dev/null &&
|
||||
echo -l$i >> generated/optlibs.dat
|
||||
echo -n .
|
||||
done
|
||||
rm -f generated/libprobe
|
||||
echo
|
||||
fi
|
||||
|
||||
# LINK needs optlibs.dat, above
|
||||
|
||||
LINK="$(echo $LDOPTIMIZE $LDFLAGS -o "$UNSTRIPPED" $LDASNEEDED $(cat generated/optlibs.dat))"
|
||||
genbuildsh > generated/build.sh && chmod +x generated/build.sh || exit 1
|
||||
|
||||
#TODO: "make $SED && make" doesn't regenerate config.h because diff .config
|
||||
if true #isnewer generated/config.h "$KCONFIG_CONFIG"
|
||||
then
|
||||
echo "Make generated/config.h from $KCONFIG_CONFIG."
|
||||
|
||||
# This long and roundabout sed invocation is to make old versions of sed
|
||||
# happy. New ones have '\n' so can replace one line with two without all
|
||||
# the branches and tedious mucking about with hyperspace.
|
||||
# TODO: clean this up to use modern stuff.
|
||||
|
||||
$SED -n \
|
||||
-e 's/^# CONFIG_\(.*\) is not set.*/\1/' \
|
||||
-e 't notset' \
|
||||
-e 's/^CONFIG_\(.*\)=y.*/\1/' \
|
||||
-e 't isset' \
|
||||
-e 's/^CONFIG_\([^=]*\)=\(.*\)/#define CFG_\1 \2/p' \
|
||||
-e 'd' \
|
||||
-e ':notset' \
|
||||
-e 'h' \
|
||||
-e 's/.*/#define CFG_& 0/p' \
|
||||
-e 'g' \
|
||||
-e 's/.*/#define USE_&(...)/p' \
|
||||
-e 'd' \
|
||||
-e ':isset' \
|
||||
-e 'h' \
|
||||
-e 's/.*/#define CFG_& 1/p' \
|
||||
-e 'g' \
|
||||
-e 's/.*/#define USE_&(...) __VA_ARGS__/p' \
|
||||
$KCONFIG_CONFIG > generated/config.h || exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f generated/mkflags ] || [ generated/mkflags -ot scripts/mkflags.c ]
|
||||
then
|
||||
do_loudly $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
|
||||
fi
|
||||
|
||||
# Process config.h and newtoys.h to generate FLAG_x macros. Note we must
|
||||
# always #define the relevant macro, even when it's disabled, because we
|
||||
# allow multiple NEWTOY() in the same C file. (When disabled the FLAG is 0,
|
||||
# so flags&0 becomes a constant 0 allowing dead code elimination.)
|
||||
|
||||
make_flagsh()
|
||||
{
|
||||
# Parse files through C preprocessor twice, once to get flags for current
|
||||
# .config and once to get flags for allyesconfig
|
||||
for I in A B
|
||||
do
|
||||
(
|
||||
# define macros and select header files with option string data
|
||||
|
||||
echo "#define NEWTOY(aa,bb,cc) aa $I bb"
|
||||
echo '#define OLDTOY(...)'
|
||||
if [ "$I" == A ]
|
||||
then
|
||||
cat generated/config.h
|
||||
else
|
||||
$SED '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h
|
||||
fi
|
||||
echo '#include "lib/toyflags.h"'
|
||||
cat generated/newtoys.h
|
||||
|
||||
# Run result through preprocessor, glue together " " gaps leftover from USE
|
||||
# macros, delete comment lines, print any line with a quoted optstring,
|
||||
# turn any non-quoted opstring (NULL or 0) into " " (because fscanf can't
|
||||
# handle "" with nothing in it, and mkflags uses that).
|
||||
|
||||
) | ${CROSS_COMPILE}${CC} -E - | \
|
||||
$SED -n -e 's/" *"//g;/^#/d;t clear;:clear;s/"/"/p;t;s/\( [AB] \).*/\1 " "/p'
|
||||
|
||||
# Sort resulting line pairs and glue them together into triplets of
|
||||
# command "flags" "allflags"
|
||||
# to feed into mkflags C program that outputs actual flag macros
|
||||
# If no pair (because command's disabled in config), use " " for flags
|
||||
# so allflags can define the appropriate zero macros.
|
||||
|
||||
done | sort -s | $SED -n -e 's/ A / /;t pair;h;s/\([^ ]*\).*/\1 " "/;x' \
|
||||
-e 'b single;:pair;h;n;:single;s/[^ ]* B //;H;g;s/\n/ /;p' | \
|
||||
tee generated/flags.raw | generated/mkflags > generated/flags.h || exit 1
|
||||
}
|
||||
|
||||
if isnewer generated/flags.h toys "$KCONFIG_CONFIG"
|
||||
then
|
||||
echo -n "generated/flags.h "
|
||||
make_flagsh
|
||||
fi
|
||||
|
||||
# Extract global structure definitions and flag definitions from toys/*/*.c
|
||||
|
||||
function getglobals()
|
||||
{
|
||||
for i in toys/*/*.c
|
||||
do
|
||||
NAME="$(echo $i | $SED 's@.*/\(.*\)\.c@\1@')"
|
||||
DATA="$($SED -n -e '/^GLOBALS(/,/^)/b got;b;:got' \
|
||||
-e 's/^GLOBALS(/struct '"$NAME"'_data {/' \
|
||||
-e 's/^)/};/' -e 'p' $i)"
|
||||
|
||||
[ ! -z "$DATA" ] && echo -e "// $i\n\n$DATA\n"
|
||||
done
|
||||
}
|
||||
|
||||
if isnewer generated/globals.h toys
|
||||
then
|
||||
echo -n "generated/globals.h "
|
||||
GLOBSTRUCT="$(getglobals)"
|
||||
(
|
||||
echo "$GLOBSTRUCT"
|
||||
echo
|
||||
echo "extern union global_union {"
|
||||
echo "$GLOBSTRUCT" | \
|
||||
$SED -n 's/struct \(.*\)_data {/ struct \1_data \1;/p'
|
||||
echo "} this;"
|
||||
) > generated/globals.h
|
||||
fi
|
||||
|
||||
if [ ! -f generated/mktags ] || [ generated/mktags -ot scripts/mktags.c ]
|
||||
then
|
||||
do_loudly $HOSTCC scripts/mktags.c -o generated/mktags || exit 1
|
||||
fi
|
||||
|
||||
if isnewer generated/tags.h toys
|
||||
then
|
||||
echo -n "generated/tags.h "
|
||||
|
||||
$SED -n '/TAGGED_ARRAY(/,/^)/{s/.*TAGGED_ARRAY[(]\([^,]*\),/\1/;p}' \
|
||||
toys/*/*.c lib/*.c | generated/mktags > generated/tags.h
|
||||
fi
|
||||
|
||||
if [ ! -f generated/config2help ] || [ generated/config2help -ot scripts/config2help.c ]
|
||||
then
|
||||
do_loudly $HOSTCC scripts/config2help.c -o generated/config2help || exit 1
|
||||
fi
|
||||
if isnewer generated/help.h generated/Config.in
|
||||
then
|
||||
echo "generated/help.h"
|
||||
generated/config2help Config.in $KCONFIG_CONFIG > generated/help.h || exit 1
|
||||
fi
|
||||
|
||||
[ ! -z "$NOBUILD" ] && exit 0
|
||||
|
||||
echo -n "Compile $OUTNAME"
|
||||
[ ! -z "$V" ] && echo
|
||||
DOTPROG=.
|
||||
|
||||
# This is a parallel version of: do_loudly $BUILD $FILES $LINK || exit 1
|
||||
|
||||
# Any headers newer than the oldest generated/obj file?
|
||||
X="$(ls -1t generated/obj/* 2>/dev/null | tail -n 1)"
|
||||
# TODO: redo this
|
||||
if [ ! -e "$X" ] || [ ! -z "$(find toys -name "*.h" -newer "$X")" ]
|
||||
then
|
||||
rm -rf generated/obj && mkdir -p generated/obj || exit 1
|
||||
else
|
||||
rm -f generated/obj/{main,lib_help}.o || exit 1
|
||||
fi
|
||||
|
||||
# build each generated/obj/*.o file in parallel
|
||||
|
||||
PENDING=
|
||||
LNKFILES=
|
||||
DONE=0
|
||||
COUNT=0
|
||||
CLICK=
|
||||
|
||||
for i in $LIBFILES click $TOYFILES
|
||||
do
|
||||
[ "$i" == click ] && CLICK=1 && continue
|
||||
|
||||
X=${i/lib\//lib_}
|
||||
X=${X##*/}
|
||||
OUT="generated/obj/${X%%.c}.o"
|
||||
LNKFILES="$LNKFILES $OUT"
|
||||
|
||||
# $LIBFILES doesn't need to be rebuilt if older than .config, $TOYFILES does
|
||||
# ($TOYFILES contents can depend on CONFIG symbols, lib/*.c never should.)
|
||||
|
||||
[ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] &&
|
||||
continue
|
||||
|
||||
do_loudly $BUILD -c $i -o $OUT &
|
||||
PENDING="$PENDING $!"
|
||||
COUNT=$(($COUNT+1))
|
||||
|
||||
# ratelimit to $CPUS many parallel jobs, detecting errors
|
||||
|
||||
for j in $PENDING
|
||||
do
|
||||
[ "$COUNT" -lt "$CPUS" ] && break;
|
||||
|
||||
wait $j
|
||||
DONE=$(($DONE+$?))
|
||||
COUNT=$(($COUNT-1))
|
||||
PENDING="${PENDING## $j}"
|
||||
done
|
||||
[ $DONE -ne 0 ] && break
|
||||
done
|
||||
|
||||
# wait for all background jobs, detecting errors
|
||||
|
||||
for i in $PENDING
|
||||
do
|
||||
wait $i
|
||||
DONE=$(($DONE+$?))
|
||||
done
|
||||
|
||||
[ $DONE -ne 0 ] && exit 1
|
||||
|
||||
do_loudly $BUILD $LNKFILES $LINK || exit 1
|
||||
if [ ! -z "$NOSTRIP" ] ||
|
||||
! do_loudly ${CROSS_COMPILE}${STRIP} "$UNSTRIPPED" -o "$OUTNAME"
|
||||
then
|
||||
[ -z "$NOSTRIP" ] && echo "strip failed, using unstripped"
|
||||
rm -f "$OUTNAME" &&
|
||||
cp "$UNSTRIPPED" "$OUTNAME" ||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# gcc 4.4's strip command is buggy, and doesn't set the executable bit on
|
||||
# its output the way SUSv4 suggests it do so. While we're at it, make sure
|
||||
# we don't have the "w" bit set so things like bzip2's "cp -f" install don't
|
||||
# overwrite our binary through the symlink.
|
||||
do_loudly chmod 555 "$OUTNAME" || exit 1
|
||||
|
||||
echo
|
||||
Executable
+160
@@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to build all cross and native compilers supported by musl-libc.
|
||||
# This isn't directly used by toybox, but is useful for testing.
|
||||
|
||||
if [ ! -d litecross ]
|
||||
then
|
||||
echo Run this script in musl-cross-make directory to make "ccc" directory.
|
||||
echo
|
||||
echo " "git clone https://github.com/richfelker/musl-cross-make
|
||||
echo " "cd musl-cross-make
|
||||
echo ' ~/toybox/scripts/mcm-buildall.sh'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# All toolchains after the first are themselves cross compiled (so they
|
||||
# can be statically linked against musl on the host, for binary portability.)
|
||||
# static i686 binaries are basically "poor man's x32".
|
||||
BOOTSTRAP=i686-linux-musl
|
||||
|
||||
[ -z "$OUTPUT" ] && OUTPUT="$PWD/ccc"
|
||||
|
||||
if [ "$1" == clean ]
|
||||
then
|
||||
rm -rf "$OUTPUT" host-* *.log
|
||||
make clean
|
||||
exit
|
||||
fi
|
||||
|
||||
make_toolchain()
|
||||
{
|
||||
# Set cross compiler path
|
||||
LP="$PATH"
|
||||
if [ -z "$TYPE" ]
|
||||
then
|
||||
OUTPUT="$PWD/host-$TARGET"
|
||||
EXTRASUB=y
|
||||
else
|
||||
if [ "$TYPE" == static ]
|
||||
then
|
||||
HOST=$BOOTSTRAP
|
||||
[ "$TARGET" = "$HOST" ] && LP="$PWD/host-$HOST/bin:$LP"
|
||||
TYPE=cross
|
||||
EXTRASUB=y
|
||||
LP="$OUTPUT/$HOST-cross/bin:$LP"
|
||||
else
|
||||
HOST="$TARGET"
|
||||
export NATIVE=y
|
||||
LP="$OUTPUT/${RENAME:-$TARGET}-cross/bin:$LP"
|
||||
fi
|
||||
COMMON_CONFIG="CC=\"$HOST-gcc -static --static\" CXX=\"$HOST-g++ -static --static\""
|
||||
export -n HOST
|
||||
OUTPUT="$OUTPUT/${RENAME:-$TARGET}-$TYPE"
|
||||
fi
|
||||
|
||||
if [ -e "$OUTPUT.sqf" ] || [ -e "$OUTPUT/bin/$TARGET-ld" ] ||
|
||||
[ -e "$OUTPUT/bin/ld" ]
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
# Change title bar to say what we're currently building
|
||||
|
||||
echo === building $TARGET-$TYPE
|
||||
echo -en "\033]2;$TARGET-$TYPE\007"
|
||||
|
||||
rm -rf build/"$TARGET" "$OUTPUT" &&
|
||||
if [ -z "$CPUS" ]
|
||||
then
|
||||
CPUS="$(nproc)"
|
||||
[ "$CPUS" != 1 ] && CPUS=$(($CPUS+1))
|
||||
fi
|
||||
set -x &&
|
||||
PATH="$LP" make OUTPUT="$OUTPUT" TARGET="$TARGET" \
|
||||
GCC_CONFIG="--disable-nls --disable-libquadmath --disable-decimal-float --disable-multilib --enable-languages=c,c++ $GCC_CONFIG" \
|
||||
COMMON_CONFIG="CFLAGS=\"$CFLAGS -g0 -Os\" CXXFLAGS=\"$CXXFLAGS -g0 -Os\" LDFLAGS=\"$LDFLAGS -s\" $COMMON_CONFIG" \
|
||||
install -j$CPUS || exit 1
|
||||
set +x
|
||||
echo -e '#ifndef __MUSL__\n#define __MUSL__ 1\n#endif' \
|
||||
>> "$OUTPUT/${EXTRASUB:+$TARGET/}include/features.h"
|
||||
|
||||
if [ ! -z "$RENAME" ] && [ "$TYPE" == cross ]
|
||||
then
|
||||
CONTEXT="output/$RENAME-cross/bin"
|
||||
for i in "$CONTEXT/$TARGET-"*
|
||||
do
|
||||
X="$(echo $i | sed "s@.*/$TARGET-\([^-]*\)@\1@")"
|
||||
ln -sf "$TARGET-$X" "$CONTEXT/$RENAME-$X"
|
||||
done
|
||||
fi
|
||||
|
||||
# Prevent cross compiler reusing dynamically linked host build files for
|
||||
# $BOOTSTRAP arch
|
||||
[ -z "$TYPE" ] && make clean
|
||||
|
||||
if [ "$TYPE" == native ]
|
||||
then
|
||||
# gcc looks in "../usr/include" but not "/bin/../include" (relative to the
|
||||
# executable). That means /usr/bin/gcc looks in /usr/usr/include, so that's
|
||||
# not a fix either. So add a NOP symlink as a workaround for The Crazy.
|
||||
ln -s . "$OUTPUT/usr" || exit 1
|
||||
[ ! -z "$(which mksquashfs 2>/dev/null)" ] &&
|
||||
mksquashfs "$OUTPUT" "$OUTPUT.sqf" -all-root &&
|
||||
[ -z "$CLEANUP" ] && rm -rf "$OUTPUT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Expand compressed target into binutils/gcc "tuple" and call make_toolchain
|
||||
make_tuple()
|
||||
{
|
||||
PART1=${1/:*/}
|
||||
PART3=${1/*:/}
|
||||
PART2=${1:$((${#PART1}+1)):$((${#1}-${#PART3}-${#PART1}-2))}
|
||||
|
||||
# Do we need to rename this toolchain after building it?
|
||||
RENAME=${PART1/*@/}
|
||||
[ "$RENAME" == "$PART1" ] && RENAME=
|
||||
PART1=${PART1/@*/}
|
||||
TARGET=${PART1}-linux-musl${PART2}
|
||||
|
||||
[ -z "$NOCLEAN" ] && rm -rf build
|
||||
|
||||
for TYPE in static native
|
||||
do
|
||||
TYPE=$TYPE TARGET=$TARGET GCC_CONFIG="$PART3" RENAME="$RENAME" \
|
||||
make_toolchain 2>&1 | tee "$OUTPUT"/log/${RENAME:-$PART1}-${TYPE}.log
|
||||
done
|
||||
}
|
||||
|
||||
mkdir -p "$OUTPUT"/log
|
||||
|
||||
# Make bootstrap compiler (no $TYPE, dynamically linked against host libc)
|
||||
# We build the rest of the cross compilers with this so they're linked against
|
||||
# musl-libc, because glibc doesn't fully support static linking and dynamic
|
||||
# binaries aren't really portable between distributions
|
||||
TARGET=$BOOTSTRAP make_toolchain 2>&1 | tee -a "$OUTPUT/log/$BOOTSTRAP"-host.log
|
||||
|
||||
if [ $# -gt 0 ]
|
||||
then
|
||||
for i in "$@"
|
||||
do
|
||||
make_tuple "$i"
|
||||
done
|
||||
else
|
||||
# Here's the list of cross compilers supported by this build script.
|
||||
|
||||
# First target builds a proper version of the $BOOTSTRAP compiler above,
|
||||
# which is used to build the rest (in alphabetical order)
|
||||
for i in i686:: \
|
||||
aarch64:eabi: armv4l:eabihf:"--with-arch=armv5t --with-float=soft" \
|
||||
armv5l:eabihf:--with-arch=armv5t armv7l:eabihf:--with-arch=armv7-a \
|
||||
"armv7m:eabi:--with-arch=armv7-m --with-mode=thumb --disable-libatomic --enable-default-pie" \
|
||||
armv7r:eabihf:"--with-arch=armv7-r --enable-default-pie" \
|
||||
i486:: m68k:: microblaze:: mips:: mips64:: mipsel:: powerpc:: \
|
||||
powerpc64:: powerpc64le:: s390x:: sh2eb:fdpic:--with-cpu=mj2 \
|
||||
sh4::--enable-incomplete-targets x86_64:: x86_64@x32:x32:
|
||||
do
|
||||
make_tuple "$i"
|
||||
done
|
||||
fi
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
# If you want to use toybox netcat to talk to a serial port, use this.
|
||||
|
||||
if [ ! -c "$1" ]
|
||||
then
|
||||
echo "usage: minicom.sh /dev/ttyS0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SPEED="$2"
|
||||
[ -z "$SPEED" ] && SPEED=115200
|
||||
|
||||
stty $SPEED -F "$1"
|
||||
stty raw -echo -ctlecho -F "$1"
|
||||
stty raw -echo # Need to do it on stdin, too.
|
||||
./toybox netcat -f "$1"
|
||||
stty cooked echo # Put stdin back.
|
||||
@@ -0,0 +1,257 @@
|
||||
// Take three word input lines on stdin and produce flag #defines to stdout.
|
||||
// The three words on each input lnie are command name, option string with
|
||||
// current config, option string from allyesconfig. The three are space
|
||||
// separated and the last two are in double quotes.
|
||||
|
||||
// This is intentionally crappy code because we control the inputs. It leaks
|
||||
// memory like a sieve and segfaults if malloc returns null, but does the job.
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
struct flag {
|
||||
struct flag *next;
|
||||
char *command;
|
||||
struct flag *lopt;
|
||||
};
|
||||
|
||||
int chrtype(char c)
|
||||
{
|
||||
// Does this populate a GLOBALS() variable?
|
||||
if (strchr("?&^-:#|@*; %", c)) return 1;
|
||||
|
||||
// Is this followed by a numeric argument in optstr?
|
||||
if (strchr("=<>", c)) return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// replace chopped out USE_BLAH() sections with low-ascii characters
|
||||
// showing how many flags got skipped
|
||||
|
||||
char *mark_gaps(char *flags, char *all)
|
||||
{
|
||||
char *n, *new, c;
|
||||
int bare = 1;
|
||||
|
||||
// Shell feeds in " " for blank args, leading space not meaningful.
|
||||
while (isspace(*flags)) flags++;
|
||||
while (isspace(*all)) all++;
|
||||
|
||||
n = new = strdup(all);
|
||||
while (*all) {
|
||||
// --longopt parentheticals dealt with as a unit
|
||||
if (*all == '(') {
|
||||
int len = 0;
|
||||
|
||||
while (all[len++] != ')');
|
||||
if (strncmp(flags, all, len)) {
|
||||
// bare longopts need their own skip placeholders
|
||||
if (bare) *(new++) = 1;
|
||||
} else {
|
||||
memcpy(new, all, len);
|
||||
new += len;
|
||||
flags += len;
|
||||
}
|
||||
all += len;
|
||||
continue;
|
||||
}
|
||||
c = *(all++);
|
||||
if (bare) bare = chrtype(c);
|
||||
if (*flags == c) {
|
||||
*(new++) = c;
|
||||
flags++;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = chrtype(c);
|
||||
if (!c) *(new++) = 1;
|
||||
else if (c==2) while (isdigit(*all)) all++;
|
||||
}
|
||||
*new = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Break down a command string into linked list of "struct flag".
|
||||
|
||||
struct flag *digest(char *string)
|
||||
{
|
||||
struct flag *list = NULL;
|
||||
char *err = string, c;
|
||||
|
||||
while (*string) {
|
||||
// Groups must be at end.
|
||||
if (*string == '[') break;
|
||||
|
||||
// Longopts
|
||||
if (*string == '(') {
|
||||
struct flag *new = calloc(sizeof(struct flag), 1);
|
||||
|
||||
new->command = ++string;
|
||||
|
||||
// Attach longopt to previous short opt, if any.
|
||||
if (list && list->command) {
|
||||
new->next = list->lopt;
|
||||
list->lopt = new;
|
||||
} else {
|
||||
struct flag *blank = calloc(sizeof(struct flag), 1);
|
||||
|
||||
blank->next = list;
|
||||
blank->lopt = new;
|
||||
list = blank;
|
||||
}
|
||||
// An empty longopt () would break this.
|
||||
while (*++string != ')') if (*string == '-') *string = '_';
|
||||
*(string++) = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = chrtype(*string);
|
||||
if (c == 1) string++;
|
||||
else if (c == 2) {
|
||||
if (string[1]=='-') string++;
|
||||
if (!isdigit(string[1])) {
|
||||
fprintf(stderr, "%c without number in '%s'", *string, err);
|
||||
exit(1);
|
||||
}
|
||||
while (isdigit(*++string)) {
|
||||
if (!list) {
|
||||
string++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct flag *new = calloc(sizeof(struct flag), 1);
|
||||
|
||||
new->command = string++;
|
||||
new->next = list;
|
||||
list = new;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// Parse C-style octal escape
|
||||
void octane(char *from)
|
||||
{
|
||||
unsigned char *to = (void *)from;
|
||||
|
||||
while (*from) {
|
||||
if (*from == '\\') {
|
||||
*to = 0;
|
||||
while (isdigit(*++from)) *to = (8**to)+*from-'0';
|
||||
to++;
|
||||
} else *to++ = *from++;
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char command[256], flags[1023], allflags[1024];
|
||||
char *out, *outbuf = malloc(1024*1024);
|
||||
|
||||
// Yes, the output buffer is 1 megabyte with no bounds checking.
|
||||
// See "intentionally crappy", above.
|
||||
if (!(out = outbuf)) return 1;
|
||||
|
||||
printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
|
||||
"#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n"
|
||||
"#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n");
|
||||
|
||||
for (;;) {
|
||||
struct flag *flist, *aflist, *offlist;
|
||||
char *mgaps = 0;
|
||||
unsigned bit;
|
||||
|
||||
*command = *flags = *allflags = 0;
|
||||
bit = fscanf(stdin, "%255s \"%1023[^\"]\" \"%1023[^\"]\"\n",
|
||||
command, flags, allflags);
|
||||
octane(flags);
|
||||
octane(allflags);
|
||||
|
||||
if (getenv("DEBUG"))
|
||||
fprintf(stderr, "command=%s, flags=%s, allflags=%s\n",
|
||||
command, flags, allflags);
|
||||
|
||||
if (!*command) break;
|
||||
if (bit != 3) {
|
||||
fprintf(stderr, "\nError in %s (see generated/flags.raw)\n", command);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bit = 0;
|
||||
printf("// %s %s %s\n", command, flags, allflags);
|
||||
if (*flags != ' ') mgaps = mark_gaps(flags, allflags);
|
||||
else if (*allflags != ' ') mgaps = allflags;
|
||||
// If command disabled, use allflags for OLDTOY()
|
||||
printf("#undef OPTSTR_%s\n#define OPTSTR_%s ", command, command);
|
||||
if (mgaps) printf("\"%s\"\n", mgaps);
|
||||
else printf("0\n");
|
||||
if (mgaps != allflags) free(mgaps);
|
||||
|
||||
flist = digest(flags);
|
||||
offlist = aflist = digest(allflags);
|
||||
|
||||
printf("#ifdef CLEANUP_%s\n#undef CLEANUP_%s\n#undef FOR_%s\n",
|
||||
command, command, command);
|
||||
|
||||
while (offlist) {
|
||||
char *s = (char []){0, 0, 0, 0};
|
||||
|
||||
if (!offlist->command) s = offlist->lopt->command;
|
||||
else {
|
||||
*s = *offlist->command;
|
||||
if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
|
||||
}
|
||||
printf("#undef FLAG_%s\n", s);
|
||||
offlist = offlist->next;
|
||||
}
|
||||
printf("#endif\n\n");
|
||||
|
||||
sprintf(out, "#ifdef FOR_%s\n#ifndef TT\n#define TT this.%s\n#endif\n",
|
||||
command, command);
|
||||
out += strlen(out);
|
||||
|
||||
while (aflist) {
|
||||
char *llstr = bit>31 ? "LL" : "", *s = (char []){0, 0, 0, 0};
|
||||
int enabled = 0;
|
||||
|
||||
// Output flag macro for bare longopts
|
||||
if (!aflist->command) {
|
||||
s = aflist->lopt->command;
|
||||
if (flist && flist->lopt &&
|
||||
!strcmp(flist->lopt->command, aflist->lopt->command)) enabled++;
|
||||
// Output normal flag macro
|
||||
} else {
|
||||
*s = *aflist->command;
|
||||
if (127 < (unsigned char)*s) sprintf(s, "X%02X", 127&*s);
|
||||
if (flist && flist->command && *aflist->command == *flist->command)
|
||||
enabled++;
|
||||
}
|
||||
out += sprintf(out, "#define FLAG_%s (%s%s<<%d)\n",
|
||||
s, enabled ? "1" : "FORCED_FLAG", llstr, bit++);
|
||||
aflist = aflist->next;
|
||||
if (enabled) flist = flist->next;
|
||||
}
|
||||
out = stpcpy(out, "#endif\n\n");
|
||||
}
|
||||
|
||||
if (fflush(0) && ferror(stdout)) return 1;
|
||||
|
||||
out = outbuf;
|
||||
while (*out) {
|
||||
int i = write(1, outbuf, strlen(outbuf));
|
||||
|
||||
if (i<0) return 1;
|
||||
out += i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+511
@@ -0,0 +1,511 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Clear environment variables by restarting script w/bare minimum passed through
|
||||
[ -z "$NOCLEAR" ] &&
|
||||
exec env -i NOCLEAR=1 HOME="$HOME" PATH="$PATH" LINUX="$LINUX" \
|
||||
CROSS_COMPILE="$CROSS_COMPILE" CROSS_SHORT="$CROSS_SHORT" "$0" "$@"
|
||||
|
||||
# assign command line NAME=VALUE args to env vars
|
||||
while [ $# -ne 0 ]
|
||||
do
|
||||
X="${1/=*/}"
|
||||
Y="${1#*=}"
|
||||
[ "${1/=/}" != "$1" ] && eval "export $X=\"\$Y\"" || echo "unknown $i"
|
||||
shift
|
||||
done
|
||||
|
||||
# If we're cross compiling, set appropriate environment variables.
|
||||
if [ -z "$CROSS_COMPILE" ]
|
||||
then
|
||||
echo "Building natively"
|
||||
if ! cc --static -xc - -o /dev/null <<< "int main(void) {return 0;}"
|
||||
then
|
||||
echo "Warning: host compiler can't create static binaries." >&2
|
||||
sleep 3
|
||||
fi
|
||||
else
|
||||
CROSS_PATH="$(dirname "$(which "${CROSS_COMPILE}cc")")"
|
||||
CROSS_BASE="$(basename "$CROSS_COMPILE")"
|
||||
[ -z "$CROSS_SHORT" ] && CROSS_SHORT="${CROSS_BASE/-*/}"
|
||||
echo "Cross compiling to $CROSS_SHORT"
|
||||
if [ -z "$CROSS_PATH" ]
|
||||
then
|
||||
echo "no ${CROSS_COMPILE}cc in path" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# set up directories (can override most of these paths on cmdline)
|
||||
TOP="$PWD/root"
|
||||
[ -z "$BUILD" ] && BUILD="$TOP/build"
|
||||
[ -z "$AIRLOCK" ] && AIRLOCK="$TOP/airlock"
|
||||
[ -z "$OUTPUT" ] && OUTPUT="$TOP/${CROSS_SHORT:-host}"
|
||||
[ -z "$ROOT" ] && ROOT="$OUTPUT/${CROSS_BASE}fs" && rm -rf "$ROOT"
|
||||
MYBUILD="$BUILD/${CROSS_BASE:-host-}tmp"
|
||||
rm -rf "$MYBUILD" && mkdir -p "$MYBUILD" || exit 1
|
||||
|
||||
# Stabilize cross compiling by providing known $PATH contents
|
||||
if [ ! -z "$CROSS_COMPILE" ]
|
||||
then
|
||||
if [ ! -e "$AIRLOCK/toybox" ]
|
||||
then
|
||||
echo === Create airlock dir
|
||||
|
||||
PREFIX="$AIRLOCK" KCONFIG_CONFIG="$TOP"/.airlock CROSS_COMPILE= \
|
||||
make clean defconfig toybox install_airlock &&
|
||||
rm "$TOP"/.airlock || exit 1
|
||||
fi
|
||||
export PATH="$CROSS_PATH:$AIRLOCK"
|
||||
fi
|
||||
|
||||
### Create files and directories
|
||||
mkdir -p "$ROOT"/{etc,tmp,proc,sys,dev,home,mnt,root,usr/{bin,sbin,lib},var} &&
|
||||
chmod a+rwxt "$ROOT"/tmp && ln -s usr/{bin,sbin,lib} "$ROOT" || exit 1
|
||||
|
||||
# init script. Runs as pid 1 from initramfs to set up and hand off system.
|
||||
cat > "$ROOT"/init << 'EOF' &&
|
||||
#!/bin/sh
|
||||
|
||||
export HOME=/home
|
||||
export PATH=/bin:/sbin
|
||||
|
||||
mountpoint -q proc || mount -t proc proc proc
|
||||
mountpoint -q sys || mount -t sysfs sys sys
|
||||
if ! mountpoint -q dev
|
||||
then
|
||||
mount -t devtmpfs dev dev || mdev -s
|
||||
mkdir -p dev/pts
|
||||
mountpoint -q dev/pts || mount -t devpts dev/pts dev/pts
|
||||
fi
|
||||
|
||||
if [ $$ -eq 1 ]
|
||||
then
|
||||
# Setup networking for QEMU (needs /proc)
|
||||
ifconfig eth0 10.0.2.15
|
||||
route add default gw 10.0.2.2
|
||||
[ "$(date +%s)" -lt 1000 ] && rdate 10.0.2.2 # or time-b.nist.gov
|
||||
[ "$(date +%s)" -lt 10000000 ] && ntpd -nq -p north-america.pool.ntp.org
|
||||
|
||||
[ -z "$CONSOLE" ] &&
|
||||
CONSOLE="$(sed -n 's@.* console=\(/dev/\)*\([^ ]*\).*@\2@p' /proc/cmdline)"
|
||||
|
||||
[ -z "$HANDOFF" ] && HANDOFF=/bin/sh && echo Type exit when done.
|
||||
[ -z "$CONSOLE" ] && CONSOLE=console
|
||||
exec /sbin/oneit -c /dev/"$CONSOLE" $HANDOFF
|
||||
else
|
||||
/bin/sh
|
||||
umount /dev/pts /dev /sys /proc
|
||||
fi
|
||||
EOF
|
||||
chmod +x "$ROOT"/init &&
|
||||
|
||||
# /etc/passwd with both kernel special accounts (root and nobody) + guest user
|
||||
cat > "$ROOT"/etc/passwd << 'EOF' &&
|
||||
root::0:0:root:/home/root:/bin/sh
|
||||
guest:x:500:500:guest:/home/guest:/bin/sh
|
||||
nobody:x:65534:65534:nobody:/proc/self:/dev/null
|
||||
EOF
|
||||
|
||||
# /etc/group with groups corresponding to each /etc/passwd user
|
||||
cat > "$ROOT"/etc/group << 'EOF' &&
|
||||
root:x:0:
|
||||
guest:x:500:
|
||||
nobody:x:65534:
|
||||
EOF
|
||||
|
||||
# /etc/resolv.conf using Google's public nameserver. (We could use QEMU's
|
||||
# 10.0.2.2 forwarder here, but this way works in both chroot and QEMU.)
|
||||
echo "nameserver 8.8.8.8" > "$ROOT"/etc/resolv.conf || exit 1
|
||||
|
||||
# Build toybox
|
||||
|
||||
make clean
|
||||
if [ -z .config ]
|
||||
then
|
||||
make defconfig
|
||||
# Work around musl-libc design flaw.
|
||||
[ "${CROSS_BASE/fdpic//}" != "$CROSS_BASE" ] &&
|
||||
sed -i 's/.*\(CONFIG_TOYBOX_MUSL_NOMMU_IS_BROKEN\).*/\1=y/' .config
|
||||
else
|
||||
make silentoldconfig
|
||||
fi
|
||||
LDFLAGS=--static PREFIX="$ROOT" make toybox install || exit 1
|
||||
|
||||
# Abort early if no kernel source specified
|
||||
if [ -z "$LINUX" ] || [ ! -d "$LINUX/kernel" ]
|
||||
then
|
||||
echo 'No $LINUX directory, kernel build skipped.'
|
||||
rmdir "$MYBUILD" "$BUILD" 2>/dev/null
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Which architecture are we building a kernel for?
|
||||
[ -z "$TARGET" ] && TARGET="${CROSS_BASE/-*/}"
|
||||
[ -z "$TARGET" ] && TARGET="$(uname -m)"
|
||||
|
||||
# Target-specific info in an (alphabetical order) if/else staircase
|
||||
# Each target needs board config, serial console, RTC, ethernet, block device.
|
||||
|
||||
if [ "$TARGET" == armv5l ]
|
||||
then
|
||||
|
||||
# This could use the same VIRT board as armv7, but let's demonstrate a
|
||||
# different one requiring a separate device tree binary.
|
||||
QEMU="qemu-system-arm -M versatilepb -net nic,model=rtl8139 -net user"
|
||||
KARCH=arm
|
||||
KARGS="console=ttyAMA0"
|
||||
VMLINUX=arch/arm/boot/zImage
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_CPU_ARM926T=y
|
||||
CONFIG_MMU=y
|
||||
CONFIG_VFP=y
|
||||
CONFIG_ARM_THUMB=y
|
||||
CONFIG_AEABI=y
|
||||
CONFIG_ARCH_VERSATILE=y
|
||||
|
||||
# The switch to device-tree-only added this mess
|
||||
CONFIG_ATAGS=y
|
||||
CONFIG_DEPRECATED_PARAM_STRUCT=y
|
||||
CONFIG_ARM_ATAG_DTB_COMPAT=y
|
||||
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND=y
|
||||
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_PL031=y
|
||||
CONFIG_RTC_HCTOSYS=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCI_VERSATILE=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_SCSI=y
|
||||
CONFIG_SCSI_LOWLEVEL=y
|
||||
CONFIG_SCSI_SYM53C8XX_2=y
|
||||
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
|
||||
CONFIG_SCSI_SYM53C8XX_MMIO=y
|
||||
|
||||
CONFIG_NET_VENDOR_REALTEK=y
|
||||
CONFIG_8139CP=y
|
||||
"
|
||||
DTB=arch/arm/boot/dts/versatile-pb.dtb
|
||||
elif [ "$TARGET" == armv7l ] || [ "$TARGET" == aarch64 ]
|
||||
then
|
||||
if [ "$TARGET" == aarch64 ]
|
||||
then
|
||||
QEMU="qemu-system-aarch64 -M virt -cpu cortex-a57"
|
||||
KARCH=arm64
|
||||
VMLINUX=arch/arm64/boot/Image
|
||||
else
|
||||
QEMU="qemu-system-arm -M virt"
|
||||
KARCH=arm
|
||||
VMLINUX=arch/arm/boot/zImage
|
||||
fi
|
||||
KARGS="console=ttyAMA0"
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_MMU=y
|
||||
CONFIG_ARCH_MULTI_V7=y
|
||||
CONFIG_ARCH_VIRT=y
|
||||
CONFIG_SOC_DRA7XX=y
|
||||
CONFIG_ARCH_OMAP2PLUS_TYPICAL=y
|
||||
CONFIG_ARCH_ALPINE=y
|
||||
CONFIG_ARM_THUMB=y
|
||||
CONFIG_VDSO=y
|
||||
CONFIG_CPU_IDLE=y
|
||||
CONFIG_ARM_CPUIDLE=y
|
||||
CONFIG_KERNEL_MODE_NEON=y
|
||||
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_HCTOSYS=y
|
||||
CONFIG_RTC_DRV_PL031=y
|
||||
|
||||
CONFIG_NET_CORE=y
|
||||
CONFIG_VIRTIO_MENU=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCI_HOST_GENERIC=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
|
||||
CONFIG_ATA=y
|
||||
CONFIG_ATA_SFF=y
|
||||
CONFIG_ATA_BMDMA=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
|
||||
CONFIG_PATA_PLATFORM=y
|
||||
CONFIG_PATA_OF_PLATFORM=y
|
||||
CONFIG_ATA_GENERIC=y
|
||||
"
|
||||
elif [ "$TARGET" == i486 ] || [ "$TARGET" == i686 ] ||
|
||||
[ "$TARGET" == x86_64 ] || [ "$TARGET" == x32 ]
|
||||
then
|
||||
if [ "$TARGET" == i486 ]
|
||||
then
|
||||
QEMU="qemu-system-i386 -cpu 486 -global fw_cfg.dma_enabled=false"
|
||||
KERNEL_CONFIG="CONFIG_M486=y"
|
||||
elif [ "$TARGET" == i686 ]
|
||||
then
|
||||
QEMU="qemu-system-i386 -cpu pentium3"
|
||||
KERNEL_CONFIG="CONFIG_MPENTIUMII=y"
|
||||
else
|
||||
QEMU=qemu-system-x86_64
|
||||
KERNEL_CONFIG="CONFIG_64BIT=y"
|
||||
[ "$TARGET" == x32 ] && KERNEL_CONFIG="$KERNEL_CONFIG
|
||||
CONFIG_X86_X32=y"
|
||||
fi
|
||||
KARCH=x86
|
||||
KARGS="console=ttyS0"
|
||||
VMLINUX=arch/x86/boot/bzImage
|
||||
CONFIG_MPENTIUMII=y
|
||||
KERNEL_CONFIG="
|
||||
$KERNEL_CONFIG
|
||||
|
||||
CONFIG_UNWINDER_FRAME_POINTER=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_ATA=y
|
||||
CONFIG_ATA_SFF=y
|
||||
CONFIG_ATA_BMDMA=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
|
||||
CONFIG_NET_VENDOR_INTEL=y
|
||||
CONFIG_E1000=y
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
"
|
||||
elif [ "$TARGET" == mips ] || [ "$TARGET" == mipsel ]
|
||||
then
|
||||
QEMU="qemu-system-mips -M malta"
|
||||
KARCH=mips
|
||||
KARGS="console=ttyS0"
|
||||
VMLINUX=vmlinux
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_MIPS_MALTA=y
|
||||
CONFIG_CPU_MIPS32_R2=y
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_ATA=y
|
||||
CONFIG_ATA_SFF=y
|
||||
CONFIG_ATA_BMDMA=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
|
||||
CONFIG_NET_VENDOR_AMD=y
|
||||
CONFIG_PCNET32=y
|
||||
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
"
|
||||
[ "$TARGET" == mipsel ] &&
|
||||
KERNEL_CONFIG="${KERNEL_CONFIG}CONFIG_CPU_LITTLE_ENDIAN=y" &&
|
||||
QEMU="qemu-system-mipsel -M malta"
|
||||
elif [ "$TARGET" == powerpc ]
|
||||
then
|
||||
KARCH=powerpc
|
||||
QEMU="qemu-system-ppc -M g3beige"
|
||||
KARGS="console=ttyS0"
|
||||
VMLINUX=vmlinux
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_ALTIVEC=y
|
||||
CONFIG_PPC_PMAC=y
|
||||
CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
|
||||
|
||||
CONFIG_IDE=y
|
||||
CONFIG_IDE_GD=y
|
||||
CONFIG_IDE_GD_ATA=y
|
||||
CONFIG_BLK_DEV_IDE_PMAC=y
|
||||
CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
|
||||
|
||||
CONFIG_MACINTOSH_DRIVERS=y
|
||||
CONFIG_ADB=y
|
||||
CONFIG_ADB_CUDA=y
|
||||
|
||||
CONFIG_NET_VENDOR_NATSEMI=y
|
||||
CONFIG_NET_VENDOR_8390=y
|
||||
CONFIG_NE2K_PCI=y
|
||||
|
||||
CONFIG_SERIO=y
|
||||
CONFIG_SERIAL_PMACZILOG=y
|
||||
CONFIG_SERIAL_PMACZILOG_TTYS=y
|
||||
CONFIG_SERIAL_PMACZILOG_CONSOLE=y
|
||||
CONFIG_BOOTX_TEXT=y
|
||||
"
|
||||
elif [ "$TARGET" == powerpc64le ]
|
||||
then
|
||||
KARCH=powerpc
|
||||
QEMU="qemu-system-ppc64 -M pseries -vga none"
|
||||
KARGS="console=/dev/hvc0"
|
||||
VMLINUX=vmlinux
|
||||
KERNEL_CONFIG="CONFIG_PPC64=y
|
||||
CONFIG_PPC_PSERIES=y
|
||||
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||
CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
|
||||
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_SCSI_LOWLEVEL=y
|
||||
CONFIG_SCSI_IBMVSCSI=y
|
||||
CONFIG_ATA=y
|
||||
|
||||
CONFIG_NET_VENDOR_IBM=y
|
||||
CONFIG_IBMVETH=y
|
||||
CONFIG_HVC_CONSOLE=y
|
||||
|
||||
# None of this should be necessary
|
||||
CONFIG_PPC_TRANSACTIONAL_MEM=y
|
||||
CONFIG_PPC_DISABLE_WERROR=y
|
||||
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
|
||||
"
|
||||
elif [ "$TARGET" = s390x ]
|
||||
then
|
||||
QEMU="qemu-system-s390x"
|
||||
KARCH=s390
|
||||
VMLINUX=arch/s390/boot/bzImage
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_MARCH_Z900=y
|
||||
CONFIG_PACK_STACK=y
|
||||
CONFIG_NET_CORE=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_SCLP_TTY=y
|
||||
CONFIG_SCLP_CONSOLE=y
|
||||
CONFIG_SCLP_VT220_TTY=y
|
||||
CONFIG_SCLP_VT220_CONSOLE=y
|
||||
CONFIG_S390_GUEST=y
|
||||
"
|
||||
elif [ "$TARGET" == sh4 ]
|
||||
then
|
||||
QEMU="qemu-system-sh4 -M r2d -serial null -serial mon:stdio"
|
||||
KARCH=sh
|
||||
KARGS="console=ttySC1 noiotrap"
|
||||
VMLINUX=arch/sh/boot/zImage
|
||||
KERNEL_CONFIG="
|
||||
CONFIG_CPU_SUBTYPE_SH7751R=y
|
||||
CONFIG_MMU=y
|
||||
CONFIG_MEMORY_START=0x0c000000
|
||||
CONFIG_VSYSCALL=y
|
||||
CONFIG_SH_FPU=y
|
||||
CONFIG_SH_RTS7751R2D=y
|
||||
CONFIG_RTS7751R2D_PLUS=y
|
||||
CONFIG_SERIAL_SH_SCI=y
|
||||
CONFIG_SERIAL_SH_SCI_CONSOLE=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_NET_VENDOR_REALTEK=y
|
||||
CONFIG_8139CP=y
|
||||
|
||||
CONFIG_PCI=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_ATA=y
|
||||
CONFIG_ATA_SFF=y
|
||||
CONFIG_ATA_BMDMA=y
|
||||
CONFIG_PATA_PLATFORM=y
|
||||
|
||||
CONFIG_BINFMT_ELF_FDPIC=y
|
||||
CONFIG_BINFMT_FLAT=y
|
||||
|
||||
#CONFIG_SPI=y
|
||||
#CONFIG_SPI_SH_SCI=y
|
||||
#CONFIG_MFD_SM501=y
|
||||
|
||||
#CONFIG_RTC_CLASS=y
|
||||
#CONFIG_RTC_DRV_R9701=y
|
||||
#CONFIG_RTC_DRV_SH=y
|
||||
#CONFIG_RTC_HCTOSYS=y
|
||||
"
|
||||
else
|
||||
echo "Unknown \$TARGET"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Write the miniconfig file
|
||||
{
|
||||
echo "# make ARCH=$KARCH allnoconfig KCONFIG_ALLCONFIG=$TARGET.miniconf"
|
||||
echo "# make ARCH=$KARCH -j \$(nproc)"
|
||||
echo "# boot $VMLINUX"
|
||||
echo
|
||||
echo "$KERNEL_CONFIG"
|
||||
|
||||
# Generic options for all targets
|
||||
|
||||
echo "
|
||||
# CONFIG_EMBEDDED is not set
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_BINFMT_ELF=y
|
||||
CONFIG_BINFMT_SCRIPT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
|
||||
CONFIG_BLK_DEV=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_RD_GZIP=y
|
||||
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_USE_FOR_EXT2=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_FAT_DEFAULT_UTF8=y
|
||||
CONFIG_MISC_FILESYSTEMS=y
|
||||
CONFIG_SQUASHFS=y
|
||||
CONFIG_SQUASHFS_XATTR=y
|
||||
CONFIG_SQUASHFS_ZLIB=y
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_NETDEVICES=y
|
||||
#CONFIG_NET_CORE=y
|
||||
#CONFIG_NETCONSOLE=y
|
||||
CONFIG_ETHERNET=y
|
||||
"
|
||||
} > "$OUTPUT/miniconfig-$TARGET"
|
||||
|
||||
# Write the qemu launch script
|
||||
echo "$QEMU -nographic -no-reboot -m 256" \
|
||||
"-append \"panic=1 HOST=$TARGET $KARGS\"" \
|
||||
"-kernel $(basename "$VMLINUX") -initrd ${CROSS_BASE}root.cpio.gz" \
|
||||
${DTB:+-dtb "$(basename "$DTB")"} '"$@"' \
|
||||
> "$OUTPUT/qemu-$TARGET.sh" &&
|
||||
chmod +x "$OUTPUT/qemu-$TARGET.sh" &&
|
||||
|
||||
echo "Build linux for $KARCH"
|
||||
|
||||
# Snapshot Linux source dir and clean it
|
||||
cp -sfR "$LINUX" "$MYBUILD/linux" && pushd "$MYBUILD/linux" > /dev/null ||
|
||||
exit 1
|
||||
|
||||
# Build kernel
|
||||
make distclean &&
|
||||
make ARCH=$KARCH allnoconfig KCONFIG_ALLCONFIG="$OUTPUT/miniconfig-$TARGET" &&
|
||||
make ARCH=$KARCH CROSS_COMPILE="$CROSS_COMPILE" -j $(nproc) || exit 1
|
||||
|
||||
# If we have a device tree binary, save it for QEMU.
|
||||
if [ ! -z "$DTB" ]
|
||||
then
|
||||
cp "$DTB" "$OUTPUT/$(basename "$DTB")" || exit 1
|
||||
fi
|
||||
|
||||
cp "$VMLINUX" "$OUTPUT/$(basename "$VMLINUX")" && cd .. && rm -rf linux &&
|
||||
popd || exit 1
|
||||
rmdir "$MYBUILD" "$BUILD" 2>/dev/null
|
||||
|
||||
# package root filesystem for initramfs.
|
||||
# we do it here so module install can add files (not implemented yet)
|
||||
echo === create "${CROSS_BASE}root.cpio.gz"
|
||||
|
||||
(cd "$ROOT" && find . | cpio -o -H newc | gzip) > \
|
||||
"$OUTPUT/${CROSS_BASE}root.cpio.gz"
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Create status.html
|
||||
|
||||
import subprocess,sys
|
||||
|
||||
def readit(args, shell=False):
|
||||
ret={}
|
||||
arr=[]
|
||||
blob=subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
|
||||
for i in blob.stdout.read().split("\n"):
|
||||
if not i: continue
|
||||
i=i.split()
|
||||
try: ret[i[0]].extend(i[1:])
|
||||
except: ret[i[0]]=i[1:]
|
||||
arr.extend(i)
|
||||
return ret,arr
|
||||
|
||||
# Run sed on roadmap and source to get command lists, and run toybox too
|
||||
# This gives us a dictionary of types, each with a list of commands
|
||||
|
||||
print "Collecting data..."
|
||||
|
||||
stuff,blah=readit(["sed","-n", 's/<span id=\\([a-z_]*\\)>/\\1 /;t good;d;:good;h;:loop;n;s@</span>@@;t out;H;b loop;:out;g;s/\\n/ /g;p', "www/roadmap.html", "www/status.html"])
|
||||
blah,toystuff=readit(["./toybox"])
|
||||
blah,pending=readit(["sed -n 's/[^ \\t].*TOY(\\([^,]*\\),.*/\\1/p' toys/pending/*.c"], 1)
|
||||
blah,version=readit(["git","describe","--tags"])
|
||||
|
||||
print "Analyzing..."
|
||||
|
||||
# Create reverse mappings: reverse["command"] gives list of categories it's in
|
||||
|
||||
reverse={}
|
||||
for i in stuff:
|
||||
for j in stuff[i]:
|
||||
try: reverse[j].append(i)
|
||||
except: reverse[j]=[i]
|
||||
print "all commands=%s" % len(reverse)
|
||||
|
||||
# Run a couple sanity checks on input
|
||||
|
||||
for i in toystuff:
|
||||
if (i in pending): print "barf %s" % i
|
||||
|
||||
unknowns=[]
|
||||
for i in toystuff + pending:
|
||||
if not i in reverse: unknowns.append(i)
|
||||
|
||||
if unknowns: print "uncategorized: %s" % " ".join(unknowns)
|
||||
|
||||
conv = [("posix", '<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/%s.html">%%s</a>', "[%s]"),
|
||||
("lsb", '<a href="http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/%s.html">%%s</a>', '<%s>'),
|
||||
("development", '<a href="http://linux.die.net/man/1/%s">%%s</a>', '(%s)'),
|
||||
("toolbox", "", '{%s}'), ("klibc_cmd", "", '=%s='),
|
||||
("sash_cmd", "", '#%s#'), ("sbase_cmd", "", '@%s@'),
|
||||
("beastiebox_cmd", "", '*%s*'), ("tizen", "", '$%s$'),
|
||||
("shell", "", "%%%s%%"),
|
||||
("request", '<a href="http://linux.die.net/man/1/%s">%%s</a>', '+%s+')]
|
||||
|
||||
|
||||
def categorize(reverse, i, skippy=""):
|
||||
linky = "%s"
|
||||
out = i
|
||||
|
||||
if skippy: types = filter(lambda a: a != skippy, reverse[i])
|
||||
else: types = reverse[i]
|
||||
|
||||
for j in conv:
|
||||
if j[0] in types:
|
||||
if j[1]: linky = j[1] % i
|
||||
out = j[2] % out
|
||||
if not skippy: break
|
||||
if (not skippy) and out == i:
|
||||
sys.stderr.write("unknown %s %s\n" % (i,reverse[i]))
|
||||
|
||||
return linky % out
|
||||
|
||||
# Sort/annotate done, pending, and todo item lists
|
||||
|
||||
allcmd=[]
|
||||
done=[]
|
||||
pend=[]
|
||||
todo=[]
|
||||
blah=list(reverse)
|
||||
blah.sort()
|
||||
for i in blah:
|
||||
out=categorize(reverse, i)
|
||||
allcmd.append(out)
|
||||
if i in toystuff or i in pending:
|
||||
if i in toystuff: done.append(out)
|
||||
else: pend.append(out)
|
||||
out='<strike>%s</strike>' % out
|
||||
else: todo.append(out)
|
||||
|
||||
print "implemented=%s" % len(toystuff)
|
||||
|
||||
# Write data to output file
|
||||
|
||||
outfile=open("www/status.gen", "w")
|
||||
outfile.write("<h1>Status of toybox %s</h1>\n" % version[0]);
|
||||
outfile.write("<h3>Legend: [posix] <lsb> (development) {android}\n")
|
||||
outfile.write("=klibc= #sash# @sbase@ *beastiebox* $tizen$ %shell% +request+ other\n")
|
||||
outfile.write("<strike>pending</strike></h3>\n");
|
||||
|
||||
outfile.write("<a name=done><h2><a href=#done>Completed</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(done))
|
||||
outfile.write("<a name=part><h2><a href=#part>Partially implemented</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(pend))
|
||||
outfile.write("<a name=todo><h2><a href=#todo>Not started yet</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(todo))
|
||||
|
||||
# Output unfinished commands by category
|
||||
|
||||
outfile.write("<hr><h2>Categories of remaining todo items</h2>")
|
||||
|
||||
for i in stuff:
|
||||
todo = []
|
||||
|
||||
for j in stuff[i]:
|
||||
if j in toystuff: continue
|
||||
if j in pending: todo.append('<strike>%s</strike>' % j)
|
||||
else: todo.append(categorize(reverse,j,i))
|
||||
|
||||
if todo:
|
||||
k = i
|
||||
for j in conv:
|
||||
if j[0] == i:
|
||||
k = j[2] % i
|
||||
|
||||
outfile.write("<a name=%s><h2><a href=#%s>%s<a></h2><blockquote><p>" % (i,i,k))
|
||||
outfile.write(" ".join(todo))
|
||||
outfile.write("</p></blockquote>\n")
|
||||
|
||||
outfile.write("<hr><a name=all><h2><a href=#all>All commands together in one big list</a></h2><blockquote><p>%s</p></blockquote>\n" % "\n".join(allcmd))
|
||||
@@ -0,0 +1,58 @@
|
||||
// Process TAGGED_ARRAY() macros to emit TAG_STRING index macros.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *tag = 0;
|
||||
int idx = 0;
|
||||
|
||||
for (;;) {
|
||||
char *line = 0, *s;
|
||||
ssize_t len;
|
||||
|
||||
len = getline(&line, (void *)&len, stdin);
|
||||
if (len<0) break;
|
||||
while (len && isspace(line[len-1])) line[--len]=0;
|
||||
|
||||
// Very simple parser: If we haven't got a TAG then first line is TAG.
|
||||
// Then look for { followed by "str" (must be on same line, may have
|
||||
// more than one per line), for each one emit #define. Current TAG ended
|
||||
// by ) at start of line.
|
||||
|
||||
if (!tag) {
|
||||
if (!isalpha(*line)) {
|
||||
fprintf(stderr, "bad tag %s\n", line);
|
||||
exit(1);
|
||||
}
|
||||
tag = strdup(line);
|
||||
idx = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (s = line; isspace(*s); s++);
|
||||
if (*s == ')') tag = 0;
|
||||
else for (;;) {
|
||||
char *start;
|
||||
|
||||
while (*s && *s != '{') s++;
|
||||
while (*s && *s != '"') s++;
|
||||
if (!*s) break;
|
||||
|
||||
start = ++s;
|
||||
while (*s && *s != '"') {
|
||||
if (!isalpha(*s) && !isdigit(*s)) *s = '_';
|
||||
s++;
|
||||
}
|
||||
printf("#define %s_%*.*s %d\n", tag, -40, (int)(s-start), start, idx);
|
||||
printf("#define _%s_%*.*s (1%s<<%d)\n", tag, -39, (int)(s-start), start,
|
||||
idx>31 ? "LL": "", idx);
|
||||
idx++;
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# sourced to find alternate names for things
|
||||
|
||||
source configure
|
||||
|
||||
if [ -z "$(command -v "${CROSS_COMPILE}${CC}")" ]
|
||||
then
|
||||
echo "No ${CROSS_COMPILE}${CC} found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$SED" ]
|
||||
then
|
||||
[ ! -z "$(command -v gsed 2>/dev/null)" ] && SED=gsed || SED=sed
|
||||
fi
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set up command recording wrapper
|
||||
|
||||
[ -z "$WRAPDIR" ] && WRAPDIR="$PWD"/record-commands && RM=$(which rm)
|
||||
[ -z "$WRAPLOG" ] && export WRAPLOG="$PWD"/log.txt
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "usage: WRAPDIR=dir WRAPLOG=log.txt record-commands COMMAND..."
|
||||
echo 'Then examine log.txt. "record-commands echo" to just setup $WRAPDIR'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$WRAPDIR/logwrapper" ]
|
||||
then
|
||||
make logwrapper
|
||||
mkdir -p "$WRAPDIR" && mv logwrapper "$WRAPDIR" || exit 1
|
||||
|
||||
echo "$PATH" | tr : '\n' | while read DIR
|
||||
do
|
||||
ls "$DIR/" | while read FILE
|
||||
do
|
||||
ln -s logwrapper "$WRAPDIR/$FILE" 2>/dev/null
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
# Delete old log (if any)
|
||||
rm -f "$WRAPLOG"
|
||||
|
||||
X=0
|
||||
if [ ! -z "$1" ]
|
||||
then
|
||||
PATH="$WRAPDIR:$PATH" "$@"
|
||||
fi
|
||||
X=$?
|
||||
[ ! -z "$RM" ] && "$RM" -rf "$WRAPDIR"
|
||||
|
||||
exit $X
|
||||
@@ -0,0 +1,213 @@
|
||||
# Simple test harness infrastructure
|
||||
#
|
||||
# Copyright 2005 by Rob Landley
|
||||
|
||||
# This file defines two main functions, "testcmd" and "optional". The
|
||||
# first performs a test, the second enables/disables tests based on
|
||||
# configuration options.
|
||||
|
||||
# The following environment variables enable optional behavior in "testing":
|
||||
# DEBUG - Show every command run by test script.
|
||||
# VERBOSE - Print the diff -u of each failed test case.
|
||||
# If equal to "fail", stop after first failed test.
|
||||
# "nopass" to not show successful tests
|
||||
#
|
||||
# The "testcmd" function takes five arguments:
|
||||
# $1) Description to display when running command
|
||||
# $2) Command line arguments to command
|
||||
# $3) Expected result (on stdout)
|
||||
# $4) Data written to file "input"
|
||||
# $5) Data written to stdin
|
||||
#
|
||||
# The "testing" function is like testcmd but takes a complete command line
|
||||
# (I.E. you have to include the command name.) The variable $C is an absolute
|
||||
# path to the command being tested, which can bypass shell builtins.
|
||||
#
|
||||
# The exit value of testcmd is the exit value of the command it ran.
|
||||
#
|
||||
# The environment variable "FAILCOUNT" contains a cumulative total of the
|
||||
# number of failed tests.
|
||||
#
|
||||
# The "optional" function is used to skip certain tests (by setting the
|
||||
# environment variable SKIP), ala:
|
||||
# optional CFG_THINGY
|
||||
#
|
||||
# The "optional" function checks the environment variable "OPTIONFLAGS",
|
||||
# which is either empty (in which case it always clears SKIP) or
|
||||
# else contains a colon-separated list of features (in which case the function
|
||||
# clears SKIP if the flag was found, or sets it to 1 if the flag was not found).
|
||||
|
||||
export FAILCOUNT=0
|
||||
export SKIP=
|
||||
|
||||
# Helper functions
|
||||
|
||||
# Check config to see if option is enabled, set SKIP if not.
|
||||
|
||||
SHOWPASS=PASS
|
||||
SHOWFAIL=FAIL
|
||||
SHOWSKIP=SKIP
|
||||
|
||||
if tty -s <&1
|
||||
then
|
||||
SHOWPASS="$(echo -e "\033[1;32m${SHOWPASS}\033[0m")"
|
||||
SHOWFAIL="$(echo -e "\033[1;31m${SHOWFAIL}\033[0m")"
|
||||
SHOWSKIP="$(echo -e "\033[1;33m${SHOWSKIP}\033[0m")"
|
||||
fi
|
||||
|
||||
optional()
|
||||
{
|
||||
option=`printf %s "$OPTIONFLAGS" | egrep "(^|:)$1(:|\$)"`
|
||||
# Not set?
|
||||
if [ -z "$1" ] || [ -z "$OPTIONFLAGS" ] || [ ${#option} -ne 0 ]
|
||||
then
|
||||
SKIP=""
|
||||
return
|
||||
fi
|
||||
SKIP=1
|
||||
}
|
||||
|
||||
skipnot()
|
||||
{
|
||||
if [ -z "$VERBOSE" ]
|
||||
then
|
||||
eval "$@" 2>/dev/null
|
||||
else
|
||||
eval "$@"
|
||||
fi
|
||||
[ $? -eq 0 ] || SKIPNEXT=1
|
||||
}
|
||||
|
||||
toyonly()
|
||||
{
|
||||
IS_TOYBOX="$("$C" --version 2>/dev/null)"
|
||||
[ "${IS_TOYBOX/toybox/}" == "$IS_TOYBOX" ] && SKIPNEXT=1
|
||||
|
||||
"$@"
|
||||
}
|
||||
|
||||
wrong_args()
|
||||
{
|
||||
if [ $# -ne 5 ]
|
||||
then
|
||||
printf "%s\n" "Test $NAME has the wrong number of arguments ($# $*)" >&2
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# The testing function
|
||||
|
||||
testing()
|
||||
{
|
||||
NAME="$CMDNAME $1"
|
||||
wrong_args "$@"
|
||||
|
||||
[ -z "$1" ] && NAME=$2
|
||||
|
||||
[ -n "$DEBUG" ] && set -x
|
||||
|
||||
if [ -n "$SKIP" -o -n "$SKIP_HOST" -a -n "$TEST_HOST" -o -n "$SKIPNEXT" ]
|
||||
then
|
||||
[ ! -z "$VERBOSE" ] && printf "%s\n" "$SHOWSKIP: $NAME"
|
||||
unset SKIPNEXT
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -ne "$3" > expected
|
||||
echo -ne "$4" > input
|
||||
echo -ne "$5" | ${EVAL:-eval} -- "$2" > actual
|
||||
RETVAL=$?
|
||||
|
||||
# Catch segfaults
|
||||
[ $RETVAL -gt 128 ] && [ $RETVAL -lt 255 ] &&
|
||||
echo "exited with signal (or returned $RETVAL)" >> actual
|
||||
DIFF="$(diff -au${NOSPACE:+w} expected actual)"
|
||||
if [ ! -z "$DIFF" ]
|
||||
then
|
||||
FAILCOUNT=$(($FAILCOUNT+1))
|
||||
printf "%s\n" "$SHOWFAIL: $NAME"
|
||||
if [ -n "$VERBOSE" ]
|
||||
then
|
||||
[ ! -z "$4" ] && printf "%s\n" "echo -ne \"$4\" > input"
|
||||
printf "%s\n" "echo -ne '$5' |$EVAL $2"
|
||||
printf "%s\n" "$DIFF"
|
||||
[ "$VERBOSE" == fail ] && exit 1
|
||||
fi
|
||||
else
|
||||
[ "$VERBOSE" != "nopass" ] && printf "%s\n" "$SHOWPASS: $NAME"
|
||||
fi
|
||||
rm -f input expected actual
|
||||
|
||||
[ -n "$DEBUG" ] && set +x
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
testcmd()
|
||||
{
|
||||
wrong_args "$@"
|
||||
|
||||
X="$1"
|
||||
[ -z "$X" ] && X="$CMDNAME $2"
|
||||
testing "$X" "\"$C\" $2" "$3" "$4" "$5"
|
||||
}
|
||||
|
||||
# Recursively grab an executable and all the libraries needed to run it.
|
||||
# Source paths beginning with / will be copied into destpath, otherwise
|
||||
# the file is assumed to already be there and only its library dependencies
|
||||
# are copied.
|
||||
|
||||
mkchroot()
|
||||
{
|
||||
[ $# -lt 2 ] && return
|
||||
|
||||
echo -n .
|
||||
|
||||
dest=$1
|
||||
shift
|
||||
for i in "$@"
|
||||
do
|
||||
[ "${i:0:1}" == "/" ] || i=$(which $i)
|
||||
[ -f "$dest/$i" ] && continue
|
||||
if [ -e "$i" ]
|
||||
then
|
||||
d=`echo "$i" | grep -o '.*/'` &&
|
||||
mkdir -p "$dest/$d" &&
|
||||
cat "$i" > "$dest/$i" &&
|
||||
chmod +x "$dest/$i"
|
||||
else
|
||||
echo "Not found: $i"
|
||||
fi
|
||||
mkchroot "$dest" $(ldd "$i" | egrep -o '/.* ')
|
||||
done
|
||||
}
|
||||
|
||||
# Set up a chroot environment and run commands within it.
|
||||
# Needed commands listed on command line
|
||||
# Script fed to stdin.
|
||||
|
||||
dochroot()
|
||||
{
|
||||
mkdir tmpdir4chroot
|
||||
mount -t ramfs tmpdir4chroot tmpdir4chroot
|
||||
mkdir -p tmpdir4chroot/{etc,sys,proc,tmp,dev}
|
||||
cp -L testing.sh tmpdir4chroot
|
||||
|
||||
# Copy utilities from command line arguments
|
||||
|
||||
echo -n "Setup chroot"
|
||||
mkchroot tmpdir4chroot $*
|
||||
echo
|
||||
|
||||
mknod tmpdir4chroot/dev/tty c 5 0
|
||||
mknod tmpdir4chroot/dev/null c 1 3
|
||||
mknod tmpdir4chroot/dev/zero c 1 5
|
||||
|
||||
# Copy script from stdin
|
||||
|
||||
cat > tmpdir4chroot/test.sh
|
||||
chmod +x tmpdir4chroot/test.sh
|
||||
chroot tmpdir4chroot /test.sh
|
||||
umount -l tmpdir4chroot
|
||||
rmdir tmpdir4chroot
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright 2006 Rob Landley <rob@landley.net>
|
||||
|
||||
# Dumb little utility function to print out the assembly dump of a single
|
||||
# function, or list the functions so dumpable in an executable. You'd think
|
||||
# there would be a way to get objdump to do this, but I can't find it.
|
||||
|
||||
[ $# -lt 1 ] || [ $# -gt 2 ] && { echo "usage: showasm file function"; exit 1; }
|
||||
|
||||
[ ! -f $1 ] && { echo "File $1 not found"; exit 1; }
|
||||
|
||||
if [ $# -eq 1 ]
|
||||
then
|
||||
objdump -d $1 | sed -n -e 's/^[0-9a-fA-F]* <\(.*\)>:$/\1/p'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
objdump -d $1 | sed -n -e '/./{H;$!d}' -e "x;/^.[0-9a-fA-F]* <$2>:/p"
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build a standalone toybox command
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "usage: single.sh command..." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Harvest TOYBOX_* symbols from .config
|
||||
if [ ! -e .config ]
|
||||
then
|
||||
echo "Need .config for toybox global settings. Run defconfig/menuconfig." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Force dependencies to rebuild headers if we build multiplexer after this.
|
||||
touch -c .config
|
||||
|
||||
export KCONFIG_CONFIG=.singleconfig
|
||||
for i in "$@"
|
||||
do
|
||||
echo -n "$i:"
|
||||
TOYFILE="$(egrep -l "TOY[(]($i)[ ,]" toys/*/*.c)"
|
||||
|
||||
if [ -z "$TOYFILE" ]
|
||||
then
|
||||
echo "Unknown command '$i'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enable stuff this command depends on
|
||||
DEPENDS="$(sed -n "/^config *$i"'$/,/^$/{s/^[ \t]*depends on //;T;s/[!][A-Z0-9_]*//g;s/ *&& */|/g;p}' $TOYFILE | xargs | tr ' ' '|')"
|
||||
|
||||
NAME=$(echo $i | tr a-z- A-Z_)
|
||||
make allnoconfig > /dev/null &&
|
||||
sed -ri -e '/CONFIG_TOYBOX/d' \
|
||||
-e "s/# (CONFIG_($NAME|${NAME}_.*${DEPENDS:+|$DEPENDS})) is not set/\1=y/" \
|
||||
"$KCONFIG_CONFIG" &&
|
||||
echo "# CONFIG_TOYBOX is not set" >> "$KCONFIG_CONFIG" &&
|
||||
grep "CONFIG_TOYBOX_" .config >> "$KCONFIG_CONFIG" &&
|
||||
|
||||
rm -f "$PREFIX$i" &&
|
||||
OUTNAME="$PREFIX$i" scripts/make.sh || exit 1
|
||||
done
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
|
||||
source scripts/runtest.sh
|
||||
source scripts/portability.sh
|
||||
|
||||
TOPDIR="$PWD"
|
||||
FILES="$PWD"/tests/files
|
||||
|
||||
trap 'kill $(jobs -p) 2>/dev/null; exit 1' INT
|
||||
|
||||
rm -rf generated/testdir
|
||||
mkdir -p generated/testdir/testdir
|
||||
|
||||
if [ -z "$TEST_HOST" ]
|
||||
then
|
||||
if [ $# -ne 0 ]
|
||||
then
|
||||
PREFIX=generated/testdir/ scripts/single.sh "$@" || exit 1
|
||||
else
|
||||
make install_flat PREFIX=generated/testdir || exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd generated/testdir
|
||||
PATH="$PWD:$PATH"
|
||||
TESTDIR="$PWD"
|
||||
export LC_COLLATE=C
|
||||
|
||||
[ -f "$TOPDIR/generated/config.h" ] &&
|
||||
export OPTIONFLAGS=:$(echo $($SED -nr 's/^#define CFG_(.*) 1/\1/p' "$TOPDIR/generated/config.h") | $SED 's/ /:/g')
|
||||
|
||||
do_test()
|
||||
{
|
||||
cd "$TESTDIR" && rm -rf testdir && mkdir testdir && cd testdir || exit 1
|
||||
CMDNAME="${1##*/}"
|
||||
CMDNAME="${CMDNAME%.test}"
|
||||
if [ -z "$TEST_HOST" ]
|
||||
then
|
||||
C="$TESTDIR/$CMDNAME"
|
||||
[ ! -e "$C" ] && echo "$CMDNAME disabled" && return
|
||||
else
|
||||
C="$(which $CMDNAME 2>/dev/null)"
|
||||
[ -z "$C" ] && "C=$CMDNAME"
|
||||
fi
|
||||
|
||||
. "$1"
|
||||
}
|
||||
|
||||
if [ $# -ne 0 ]
|
||||
then
|
||||
for i in "$@"
|
||||
do
|
||||
do_test "$TOPDIR"/tests/$i.test
|
||||
done
|
||||
else
|
||||
for i in "$TOPDIR"/tests/*.test
|
||||
do
|
||||
[ -z "$TEST_ALL" ] && [ ! -x "$i" ] && continue
|
||||
do_test "$i"
|
||||
done
|
||||
fi
|
||||
@@ -0,0 +1,8 @@
|
||||
The build infrastructure adds a "make test_NAME" target for each NAME.test
|
||||
file in this directory, and "make tests" iterates through all of them.
|
||||
|
||||
Individual tests boil down to a call to "scripts/test.sh NAME", and
|
||||
testing all is "scripts/test.sh" with no arguments.
|
||||
|
||||
The test infrastructure, including the shell functions each test calls
|
||||
(mostly "testcmd" and "optional") is described in scripts/test.sh
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
testcmd "simple" "" "c2ltcGxlCg==\n" "" "simple\n"
|
||||
testcmd "file" "input" "c2ltcGxlCg==\n" "simple\n" ""
|
||||
testcmd "simple -d" "-d" "simple\n" "" "c2ltcGxlCg==\n"
|
||||
testcmd "simple -d" "-d input" "simple\n" "c2ltcGxlCg==" ""
|
||||
testcmd "default wrap" "" \
|
||||
"V2UndmUgcmVwbGFjZWQgdGhlIGRpbGl0aGl1bSB0aGV5IG5vcm1hbGx5IHVzZSB3aXRoIEZvbGdl\ncidzIENyeXN0YWxzLg==\n" \
|
||||
"" "We've replaced the dilithium they normally use with Folger's Crystals."
|
||||
testcmd "multiline -d " "-d" \
|
||||
"We've replaced the dilithium they normally use with Folger's Crystals." "" \
|
||||
"V2UndmUgcmVwbGFjZWQgdGhlIGRpbGl0aGl1bSB0aGV5IG5vcm1hbGx5IHVzZSB3aXRoIEZvbGdl\ncidzIENyeXN0YWxzLg==\n"
|
||||
|
||||
testcmd "-w" "-w 10" \
|
||||
"TWFyY2hpbm\ncgdG8gdGhl\nIGJlYXQgb2\nYgYSBkaWZm\nZXJlbnQga2\nV0dGxlIG9m\nIGZpc2guCg\n==\n" \
|
||||
"" "Marching to the beat of a different kettle of fish.\n"
|
||||
|
||||
testcmd "-w0" "-w0 input" \
|
||||
"VmlraW5ncz8gVGhlcmUgYWluJ3Qgbm8gdmlraW5ncyBoZXJlLiBKdXN0IHVzIGhvbmVzdCBmYXJtZXJzLiBUaGUgdG93biB3YXMgYnVybmluZywgdGhlIHZpbGxhZ2VycyB3ZXJlIGRlYWQuIFRoZXkgZGlkbid0IG5lZWQgdGhvc2Ugc2hlZXAgYW55d2F5LiBUaGF0J3Mgb3VyIHN0b3J5IGFuZCB3ZSdyZSBzdGlja2luZyB0byBpdC4K" \
|
||||
"Vikings? There ain't no vikings here. Just us honest farmers. The town was burning, the villagers were dead. They didn't need those sheep anyway. That's our story and we're sticking to it.\n" ""
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
# Removal of extra /'s
|
||||
testcmd "/-only" "///////" "/\n" "" ""
|
||||
testcmd "trailing /" "a//////" "a\n" "" ""
|
||||
testcmd "combined" "/////a///b///c///d/////" "d\n" "" ""
|
||||
|
||||
# Standard suffix behavior.
|
||||
testcmd "suffix" "a/b/c/d.suffix .suffix" "d\n" "" ""
|
||||
|
||||
# A suffix cannot be the entire result.
|
||||
testcmd "suffix=result" ".txt .txt" ".txt\n" "" ""
|
||||
|
||||
# Deal with suffix appearing in the filename
|
||||
testcmd "reappearing suffix 1" "a.txt.txt .txt" "a.txt\n" "" ""
|
||||
testcmd "reappearing suffix 2" "a.txt.old .txt" "a.txt.old\n" "" ""
|
||||
|
||||
# A suffix should be a real suffix, only a the end.
|
||||
testcmd "invalid suffix" "isthisasuffix? suffix" "isthisasuffix?\n" "" ""
|
||||
|
||||
# Zero-length suffix
|
||||
testcmd "zero-length suffix" "a/b/c ''" "c\n" "" ""
|
||||
|
||||
# -s.
|
||||
testcmd "-s" "-s .txt /a/b/c.txt" "c\n" "" ""
|
||||
testcmd "-s implies -a" "-s .txt /a/b/c.txt /a/b/d.txt" "c\nd\n" "" ""
|
||||
testcmd "-a" "-a /a/b/f1 /c/d/f2" "f1\nf2\n" "" ""
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testcmd "name "args" "result" "infile" "stdin"
|
||||
|
||||
BDIR="$FILES/bc"
|
||||
TESTDIR="./"
|
||||
|
||||
run_bc_test() {
|
||||
tst="$1"
|
||||
results=$(cat "$BDIR/${tst}_results.txt")
|
||||
testcmd "$tst" "-l $BDIR/$tst.txt" "$results\n" "$BDIR/$tst.txt" ""
|
||||
}
|
||||
|
||||
run_bc_test decimal
|
||||
run_bc_test add
|
||||
run_bc_test subtract
|
||||
run_bc_test multiply
|
||||
run_bc_test divide
|
||||
run_bc_test modulus
|
||||
run_bc_test power
|
||||
run_bc_test sqrt
|
||||
run_bc_test vars
|
||||
run_bc_test boolean
|
||||
run_bc_test parse
|
||||
run_bc_test print
|
||||
run_bc_test exponent
|
||||
run_bc_test log
|
||||
run_bc_test pi
|
||||
run_bc_test arctan
|
||||
run_bc_test sine
|
||||
run_bc_test cosine
|
||||
run_bc_test bessel
|
||||
run_bc_test arrays
|
||||
run_bc_test misc
|
||||
run_bc_test misc1
|
||||
run_bc_test misc2
|
||||
|
||||
testcmd "stdin" "" "2\n" "" "1+1\n"
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
function BLKID()
|
||||
{
|
||||
file=$1
|
||||
shift
|
||||
bzcat $FILES/blkid/$file.bz2 > temp.img
|
||||
# e2fsprogs' blkid outputs trailing spaces; no other blkid does.
|
||||
blkid "$@" temp.img | sed 's/ $//'
|
||||
rm temp.img
|
||||
}
|
||||
|
||||
testing "cramfs" "BLKID cramfs" \
|
||||
'temp.img: LABEL="mycramfs" TYPE="cramfs"\n' "" ""
|
||||
testing "ext2" "BLKID ext2" \
|
||||
'temp.img: LABEL="myext2" UUID="e59093ba-4135-4fdb-bcc4-f20beae4dfaf" TYPE="ext2"\n' \
|
||||
"" ""
|
||||
testing "ext3" "BLKID ext3" \
|
||||
'temp.img: LABEL="myext3" UUID="79d1c877-1a0f-4e7d-b21d-fc32ae3ef101" SEC_TYPE="ext2" TYPE="ext3"\n' \
|
||||
"" ""
|
||||
testing "ext4" "BLKID ext4" \
|
||||
'temp.img: LABEL="myext4" UUID="dc4b7c00-c0c0-4600-af7e-0335f09770fa" TYPE="ext4"\n' \
|
||||
"" ""
|
||||
testing "f2fs" "BLKID f2fs" \
|
||||
'temp.img: LABEL="myf2fs" UUID="b53d3619-c204-4c0b-8504-36363578491c" TYPE="f2fs"\n' \
|
||||
"" ""
|
||||
testing "msdos" "BLKID msdos" \
|
||||
'temp.img: SEC_TYPE="msdos" LABEL="mymsdos" UUID="6E1E-0851" TYPE="vfat"\n' \
|
||||
"" ""
|
||||
|
||||
# We use -s here because toybox blkid can't do ntfs volume labels yet.
|
||||
testing "ntfs" "BLKID ntfs -s UUID -s TYPE" \
|
||||
'temp.img: UUID="6EE1BF3808608585" TYPE="ntfs"\n' "" ""
|
||||
testing "reiserfs" "BLKID reiser3" \
|
||||
'temp.img: LABEL="myreiser" UUID="a5b99bec-45cc-41d7-986e-32f4b6fc28f2" TYPE="reiserfs"\n' \
|
||||
"" ""
|
||||
testing "squashfs" "BLKID squashfs" 'temp.img: TYPE="squashfs"\n' "" ""
|
||||
testing "vfat" "BLKID vfat" \
|
||||
'temp.img: SEC_TYPE="msdos" LABEL="myvfat" UUID="7356-B91D" TYPE="vfat"\n' \
|
||||
"" ""
|
||||
testing "xfs" "BLKID xfs" \
|
||||
'temp.img: LABEL="XFS_test" UUID="d63a1dc3-27d5-4dd4-8b38-f4f97f495c6f" TYPE="xfs"\n' \
|
||||
"" ""
|
||||
|
||||
# Unlike util-linux's blkid, toybox blkid can read from stdin.
|
||||
toyonly testing "stdin" "bzcat $FILES/blkid/squashfs.bz2 | blkid -" \
|
||||
'-: TYPE="squashfs"\n' "" ""
|
||||
|
||||
#testing "minix" 'bzcat "$BDIR"/minix.bz2 | blkid -'
|
||||
#adfs bfs btrfs cramfs jfs nilfs romfs
|
||||
#vfat // fat32 fat12 fat16
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
testing "2 known files" \
|
||||
'bzcat "$FILES/blkid/"{minix,ntfs}.bz2 | sha1sum | cut -d " " -f 1' \
|
||||
'c0b7469c9660d6056a988ef8a7fe73925efc9266\n' '' ''
|
||||
|
||||
testing "overflow" \
|
||||
'bzcat "$FILES/bzcat/overflow.bz2" >/dev/null 2>/dev/null ;
|
||||
[ $? -ne 0 ] && echo good' "good\n" "" ""
|
||||
|
||||
testing "badcrc" \
|
||||
'bzcat "$FILES/bzcat/badcrc.bz2" > /dev/null 2>/dev/null ;
|
||||
[ $? -ne 0 ] && echo good' "good\n" "" ""
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
echo "one" > file1
|
||||
echo "two" > file2
|
||||
testing "cat" "cat && echo yes" "oneyes\n" "" "one"
|
||||
testing "-" "cat - && echo yes" "oneyes\n" "" "one"
|
||||
testing "file1 file2" "cat file1 file2" "one\ntwo\n" "" ""
|
||||
testing "- file" "cat - file1" "zero\none\n" "" "zero\n"
|
||||
testing "file -" "cat file1 -" "one\nzero\n" "" "zero\n"
|
||||
|
||||
testing "file1 notfound file2" \
|
||||
"cat file1 notfound file2 2>stderr && echo ok ; cat stderr; rm stderr" \
|
||||
"one\ntwo\ncat: notfound: No such file or directory\n" "" ""
|
||||
|
||||
FILE="$(readlink -f /proc/self/exe)"
|
||||
testing "file1" \
|
||||
'cat "$FILE" > file1 && cmp "$FILE" file1 && echo yes' \
|
||||
"yes\n" "" ""
|
||||
|
||||
testing "- file1" \
|
||||
"cat - file1 | diff -a -U 0 - file1 | tail -n 1" \
|
||||
"-hello\n" "" "hello\n"
|
||||
|
||||
testing "> /dev/full" \
|
||||
"cat - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
|
||||
"cat: xwrite: No space left on device\n" "" "zero\n"
|
||||
|
||||
rm file1 file2
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]
|
||||
then
|
||||
echo "$SHOWSKIP: chattr (not root)"
|
||||
return 2>/dev/null
|
||||
exit
|
||||
fi
|
||||
|
||||
# chattr - Testcases
|
||||
|
||||
mkdir testattr
|
||||
IN="cd testattr"
|
||||
OUT="cd .."
|
||||
_t="abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
testing "[-/+]i FILE[write]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && lsattr testFile && echo "$_t" > testFile;
|
||||
chattr -i testFile; rm -rf testFile; $OUT " "----i-------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[re-write]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && echo \"$_t\" > testFile || chattr -i testFile &&
|
||||
echo \"$_t\" > testFile && lsattr testFile; rm -rf testFile; $OUT" \
|
||||
"------------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[append]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && echo \"$_t\" >> testFile || lsattr testFile &&
|
||||
chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[move]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && mv testFile testFile1 || lsattr testFile &&
|
||||
chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[delete]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && rm -f testFile || lsattr testFile &&
|
||||
chattr -i testFile; rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[read]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile && cat testFile && lsattr testFile &&
|
||||
chattr -i testFile; rm -rf testFile; $OUT" "$_t\n----i-------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[write]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && echo $_t > testFile || lsattr testFile &&
|
||||
chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[re-write]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && echo $_t > testFile || lsattr testFile &&
|
||||
chattr -a testFile && echo $_t > testFile && cat testFile &&
|
||||
lsattr testFile; rm -rf testFile;
|
||||
$OUT" "-----a------- testFile\n$_t\n------------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[append]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && echo $_t >> testFile && cat testFile &&
|
||||
lsattr testFile && chattr -a testFile; rm -rf testFile; $OUT" \
|
||||
"$_t\n$_t\n-----a------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[move]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && mv testFile testFile1 || lsattr testFile &&
|
||||
chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[delete]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && rm -f testFile || lsattr testFile &&
|
||||
chattr -a testFile; rm -rf testFile; $OUT" "-----a------- testFile\n" "" ""
|
||||
testing "[-/+]a FILE[read]" "$IN && echo "$_t" > testFile &&
|
||||
chattr +a testFile && cat testFile && lsattr testFile && chattr -a testFile;
|
||||
rm -rf testFile; $OUT" "$_t\n-----a------- testFile\n" "" ""
|
||||
|
||||
for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
|
||||
do
|
||||
testing "[-/+]$attr FILE" "$IN && echo "$_t" > testFile &&
|
||||
chattr +$attr testFile && cat testFile && chattr -$attr testFile &&
|
||||
lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
|
||||
done
|
||||
|
||||
for attr in "A" "a" "c" "D" "d" "i" "j" "s" "S" "t" "T" "u"
|
||||
do
|
||||
testing "-$attr FILE" "$IN && echo "$_t" > testFile && chattr -$attr testFile &&
|
||||
cat testFile && lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
|
||||
done
|
||||
|
||||
testing "[-/+]AacDdijsStTu FILE" "$IN && echo "$_t" > testFile &&
|
||||
chattr +AacDdijsStTu testFile && cat testFile && chattr -AacDdijsStTu testFile &&
|
||||
lsattr testFile; rm -rf testFile; $OUT" "$_t\n------------- testFile\n" "" ""
|
||||
testing "[-/+]AacDdijsStTu(random) FILE" \
|
||||
"$IN && echo "$_t" > testFile &&
|
||||
chattr +AacDdijsStTu testFile && cat testFile && chattr -A testFile &&
|
||||
chattr -a testFile && chattr -c testFile && chattr -D testFile &&
|
||||
chattr -d testFile && chattr -i testFile && chattr -j testFile &&
|
||||
chattr -s testFile && chattr -S testFile && chattr -t testFile &&
|
||||
chattr -T testFile && chattr -u testFile && lsattr testFile &&
|
||||
chattr -AacDdijsStTu testFile; rm -rf testFile; $OUT" \
|
||||
"$_t\n------------- testFile\n" "" ""
|
||||
testing "[-/+]AacDdijsStTu FILE*" "$IN &&
|
||||
echo "$_t" > testFile && echo "$_t" > testFile1 &&
|
||||
echo "$_t" > testFile2 && echo "$_t" > testFile3 &&
|
||||
echo "$_t" > testFile4 && echo "$_t" > testFile5 &&
|
||||
echo "$_t" > testFile6 && echo "$_t" > testFile7 &&
|
||||
echo "$_t" > testFile8 && echo "$_t" > testFile9 &&
|
||||
echo "$_t" > testFile10 && echo "$_t" > testFile11 &&
|
||||
chattr +AacDdijsStTu testFile* &&
|
||||
cat testFile9 && chattr -AacDdijsStTu testFile* && lsattr testFile*; rm -rf testFile*; $OUT" \
|
||||
"$_t\n------------- testFile\n------------- testFile1\n------------- testFile10\n------------- testFile11\n------------- testFile2\n------------- testFile3\n------------- testFile4\n------------- testFile5\n------------- testFile6\n------------- testFile7\n------------- testFile8\n------------- testFile9\n" "" ""
|
||||
testing "[-/+]AacDdijsStTu(random) FILE*" \
|
||||
"$IN && echo "$_t" > testFile &&
|
||||
chattr +AacDdijsStTu testFile* && cat testFile && chattr -A testFile* &&
|
||||
chattr -a testFile* && chattr -c testFile* && chattr -D testFile* &&
|
||||
chattr -d testFile* && chattr -i testFile* && chattr -j testFile* &&
|
||||
chattr -s testFile* && chattr -S testFile* && chattr -t testFile* &&
|
||||
chattr -T testFile* && chattr -u testFile* && lsattr testFile;
|
||||
rm -rf testFile; $OUT" \
|
||||
"$_t\n------------- testFile\n" "" ""
|
||||
testing "[-/+]i FILE[write]" \
|
||||
"$IN && echo "$_t" > testFile &&
|
||||
chattr +i testFile &&
|
||||
echo \"$_t\" > testFile || lsattr testFile && chattr -i testFile;
|
||||
rm -rf testFile; $OUT" "----i-------- testFile\n" "" ""
|
||||
testing "[-/+]A FILE[write]" \
|
||||
"$IN && echo "$_t" > testFile && chattr +A testFile &&
|
||||
echo \"$_t\" > testFile && lsattr testFile && chattr -A testFile;
|
||||
rm -rf testFile; $OUT" "-------A----- testFile\n" "" ""
|
||||
testing "[-/+]s FILE[write]" \
|
||||
"$IN && echo "$_t" > testFile && chattr +s testFile &&
|
||||
echo \"$_t\" > testFile && lsattr testFile && chattr -s testFile
|
||||
rm -rf testFile; $OUT" "s------------ testFile\n" "" ""
|
||||
testing "-v version FILE[write]" \
|
||||
"$IN && echo "$_t" > testFile &&
|
||||
chattr -v 1234 testFile && echo \"$_t\" > testFile &&
|
||||
lsattr -v testFile; rm -rf testFile" \
|
||||
" 1234 ------------- testFile\n" "" ""
|
||||
|
||||
_a="-------A-----"
|
||||
testing "-R [-/+]a FILE" "$IN && touch aa && chattr -R +A aa && lsattr aa &&
|
||||
chattr -R -A aa; rm -rf aa; $OUT" "$_a aa\n" "" ""
|
||||
testing "-R [-/+]a FILE.." "$IN && touch aa bb &&
|
||||
chattr -R +A aa bb && lsattr aa bb &&
|
||||
chattr -R -A aa bb; rm -rf aa bb; $OUT" "$_a aa\n$_a bb\n" "" ""
|
||||
|
||||
# Clean up
|
||||
rm -rf testattr
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]
|
||||
then
|
||||
echo "$SHOWSKIP: chgrp (not root)"
|
||||
return 2>/dev/null
|
||||
exit
|
||||
fi
|
||||
|
||||
# We chgrp between "root" and the last group in /etc/group.
|
||||
GRP="$(sed -n '$s/:.*//p' /etc/group)"
|
||||
# Or if that fails, assume we're on Android and pick a well-known group.
|
||||
: "${GRP:=shell}"
|
||||
|
||||
# Set up a little testing hierarchy
|
||||
|
||||
rm -rf testdir &&
|
||||
mkdir -p testdir/dir/dir/dir testdir/dir2 &&
|
||||
touch testdir/dir/file &&
|
||||
ln -s ../dir/dir testdir/dir2/dir &&
|
||||
ln -s ../dir/file testdir/dir2/file || exit 1
|
||||
|
||||
# Wrapper to reset groups and return results
|
||||
|
||||
IN="cd testdir && chgrp -R $GRP dir dir2 &&"
|
||||
OUT="&& cd .. && echo \$(ls -lR testdir | awk '{print \$4}')"
|
||||
|
||||
# The groups returned by $OUT are, in order:
|
||||
# dir dir2 dir/dir dir/file dir/dir/dir dir2/dir dir2/file
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
# Basic smoketest
|
||||
testing "dir" "$IN chgrp root dir $OUT" \
|
||||
"root $GRP $GRP $GRP $GRP $GRP $GRP\n" "" ""
|
||||
testing "file" "$IN chgrp root dir/file $OUT" \
|
||||
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
|
||||
testing "dir and file" "$IN chgrp root dir dir/file $OUT" \
|
||||
"root $GRP $GRP root $GRP $GRP $GRP\n" "" ""
|
||||
|
||||
# symlinks (affect target, not symlink)
|
||||
testing "symlink->file" "$IN chgrp root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
|
||||
testing "symlink->dir" "$IN chgrp root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
|
||||
testing "-h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
|
||||
|
||||
# What does -h do (affect symlink, not target)
|
||||
testing "-h symlink->file" "$IN chgrp -h root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
|
||||
testing "-h symlink->dir" "$IN chgrp -h root dir2/dir $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
|
||||
|
||||
# chgrp -R (note, -h is implied by -R)
|
||||
|
||||
testing "-R dir" "$IN chgrp -R root dir $OUT" \
|
||||
"root $GRP root root root $GRP $GRP\n" "" ""
|
||||
testing "-R dir2" "$IN chgrp -R root dir2 $OUT" \
|
||||
"$GRP root $GRP $GRP $GRP root root\n" "" ""
|
||||
testing "-R symlink->dir" "$IN chgrp -R root dir2/dir $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
|
||||
testing "-R symlink->file" "$IN chgrp -R root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
|
||||
|
||||
# chgrp -RP (same as -R by itself)
|
||||
|
||||
testing "-RP dir2" "$IN chgrp -RP root dir2 $OUT" \
|
||||
"$GRP root $GRP $GRP $GRP root root\n" "" ""
|
||||
testing "-RP symlink->dir" "$IN chgrp -RP root dir2/dir $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP root $GRP\n" "" ""
|
||||
testing "-RP symlink->file" "$IN chgrp -RP root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP $GRP $GRP $GRP root\n" "" ""
|
||||
|
||||
# chgrp -RH (change target but only recurse through symlink->dir on cmdline)
|
||||
|
||||
testing "-RH dir2" "$IN chgrp -RH root dir2 $OUT" \
|
||||
"$GRP root root root $GRP $GRP $GRP\n" "" ""
|
||||
testing "-RH symlink->dir" "$IN chgrp -RH root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
|
||||
testing "-RH symlink->file" "$IN chgrp -RH root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
|
||||
|
||||
# chgrp -RL (change target and always recurse through symlink->dir)
|
||||
|
||||
testing "-RL dir2" "$IN chgrp -RL root dir2 $OUT" \
|
||||
"$GRP root root root root $GRP $GRP\n" "" ""
|
||||
testing "-RL symlink->dir" "$IN chgrp -RL root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP root $GRP $GRP\n" "" ""
|
||||
testing "-RL symlink->file" "$IN chgrp -RL root dir2/file $OUT" \
|
||||
"$GRP $GRP $GRP root $GRP $GRP $GRP\n" "" ""
|
||||
|
||||
# -HLP are NOPs without -R
|
||||
testing "-H without -R" "$IN chgrp -H root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
|
||||
testing "-L without -R" "$IN chgrp -L root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
|
||||
testing "-P without -R" "$IN chgrp -P root dir2/dir $OUT" \
|
||||
"$GRP $GRP root $GRP $GRP $GRP $GRP\n" "" ""
|
||||
|
||||
rm -rf testdir
|
||||
Executable
+246
@@ -0,0 +1,246 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
|
||||
# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
umask 022
|
||||
|
||||
PERM="---""--x""-w-""-wx""r--""r-x""rw-""rwx"
|
||||
|
||||
num2perm()
|
||||
{
|
||||
for i in 0 1 2
|
||||
do
|
||||
num=${1:$i:1}
|
||||
printf "%s" ${PERM:$(($num*3)):3}
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
# Creating test files to test chmod command
|
||||
mkdir dir
|
||||
touch file
|
||||
|
||||
# We don't need to test all 512 permissions
|
||||
for u in 0 1 2 3 4 5 6 7
|
||||
do
|
||||
for g in 0 3 6
|
||||
do
|
||||
for o in 0 7
|
||||
do
|
||||
if [ "$type" == file ]
|
||||
then
|
||||
type=dir
|
||||
rm -rf "./$type" && mkdir $type
|
||||
DASH=d
|
||||
else
|
||||
type=file
|
||||
rm -f "./$type" && touch $type
|
||||
DASH=-
|
||||
fi
|
||||
DASHES=$(num2perm $u$g$o)
|
||||
testing "$u$g$o $type" "chmod $u$g$o $type &&
|
||||
ls -ld $type | cut -d' ' -f 1 | cut -d. -f 1" "$DASH$DASHES\n" "" ""
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "750 dir 640 file" \
|
||||
"chmod 750 dir 640 file 2>/dev/null ||
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x---\n-rwxr-x---\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "666 dir file" \
|
||||
"chmod 666 dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-rw-rw-\n-rw-rw-rw-\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "765 *" "chmod 765 * &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrw-r-x\n-rwxrw-r-x\n" "" ""
|
||||
|
||||
##### u,g,o,a=r,w,x
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u=r dir file" "chmod u=r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r-xr-x\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u=w dir file" "chmod u=w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w-r-xr-x\n--w-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u=x dir file" "chmod u=x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--xr-xr-x\n---xr--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u+r dir file" "chmod u+r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u+w dir file" "chmod u+w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u+x dir file" "chmod u+x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u-r dir file" "chmod u-r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wxr-xr-x\n--w-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u-w dir file" "chmod u-w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "u-x dir file" "chmod u-x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g=r dir file" "chmod g=r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr--r-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g=w dir file" "chmod g=w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx-w-r-x\n-rw--w-r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g=x dir file" "chmod g=x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx--xr-x\n-rw---xr--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g+r dir file" "chmod g+r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g+w dir file" "chmod g+w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrwxr-x\n-rw-rw-r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g+x dir file" "chmod g+x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r-xr--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g-r dir file" "chmod g-r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwx--xr-x\n-rw----r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g-w dir file" "chmod g-w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "g-x dir file" "chmod g-x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr--r-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o=r dir file" "chmod o=r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr--\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o=w dir file" "chmod o=w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x-w-\n-rw-r---w-\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o=x dir file" "chmod o=x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x--x\n-rw-r----x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o+r dir file" "chmod o+r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o+w dir file" "chmod o+w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xrwx\n-rw-r--rw-\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o+x dir file" "chmod o+x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r-x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o-r dir file" "chmod o-r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-x--x\n-rw-r-----\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o-w dir file" "chmod o-w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "o-x dir file" "chmod o-x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr--\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a=r dir file" "chmod a=r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r--r--\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a=w dir file" "chmod a=w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w--w--w-\n--w--w--w-\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a=x dir file" "chmod a=x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--x--x--x\n---x--x--x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a+r dir file" "chmod a+r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a+w dir file" "chmod a+w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxrwxrwx\n-rw-rw-rw-\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a+x dir file" "chmod a+x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr-xr-x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a-r dir file" "chmod a-r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wx--x--x\n--w-------\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a-w dir file" "chmod a-w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "a-x dir file" "chmod a-x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r--r--\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "=r dir file" "chmod =r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr--r--r--\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "=w dir file" "chmod =w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-w-------\n--w-------\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "=x dir file" "chmod =x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d--x--x--x\n---x--x--x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "+r dir file" "chmod +r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "+w dir file" "chmod +w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rw-r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "+x dir file" "chmod +x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drwxr-xr-x\n-rwxr-xr-x\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "-r dir file" "chmod -r dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "d-wx--x--x\n--w-------\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "-w dir file" "chmod -w dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "dr-xr-xr-x\n-r--r--r--\n" "" ""
|
||||
|
||||
rm -rf dir file && mkdir dir && touch file
|
||||
testing "-x dir file" "chmod -x dir file &&
|
||||
ls -ld dir file | cut -d' ' -f 1 | cut -d. -f 1" "drw-r--r--\n-rw-r--r--\n" "" ""
|
||||
|
||||
# Removing test files for cleanup purpose
|
||||
rm -rf dir file
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]
|
||||
then
|
||||
echo "$SHOWSKIP: chown (not root)"
|
||||
return 2>/dev/null
|
||||
exit
|
||||
fi
|
||||
|
||||
# We chown between user "root" and the last user in /etc/passwd,
|
||||
# and group "root" and the last group in /etc/group.
|
||||
USR="$(sed -n '$s/:.*//p' /etc/passwd)"
|
||||
GRP="$(sed -n '$s/:.*//p' /etc/group)"
|
||||
# Or if that fails, we assume we're on Android...
|
||||
: "${USR:=shell}"
|
||||
: "${GRP:=daemon}"
|
||||
|
||||
# Set up a little testing hierarchy
|
||||
|
||||
rm -rf testdir &&
|
||||
mkdir testdir &&
|
||||
touch testdir/file
|
||||
F=testdir/file
|
||||
|
||||
# Wrapper to reset groups and return results
|
||||
|
||||
OUT="&& stat --format '%U %G' $F"
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
# Basic smoketest
|
||||
testing "initial" "chown root:root $F $OUT" "root root\n" "" ""
|
||||
testing "usr:grp" "chown $USR:$GRP $F $OUT" "$USR $GRP\n" "" ""
|
||||
testing "root" "chown root $F $OUT" "root $GRP\n" "" ""
|
||||
# TODO: can we test "owner:"?
|
||||
testing ":grp" "chown root:root $F && chown :$GRP $F $OUT" \
|
||||
"root $GRP\n" "" ""
|
||||
testing ":" "chown $USR:$GRP $F && chown : $F $OUT" \
|
||||
"$USR $GRP\n" "" ""
|
||||
|
||||
rm -rf testdir
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
# Default behavior on stdin and on files.
|
||||
testing "on stdin" "echo -n hello | cksum" "3287646509 5\n" "" ""
|
||||
echo -n "hello" > tmpfile
|
||||
testing "on file" "cksum tmpfile" "3287646509 5 tmpfile\n" "" ""
|
||||
rm -f tmpfile
|
||||
touch one two
|
||||
testing "on multiple files" "cksum one two" "4294967295 0 one\n4294967295 0 two\n" "" ""
|
||||
rm -f one two
|
||||
|
||||
# Check the length suppression, both calculate the CRC on 'abc' but the second
|
||||
# option has length suppression on and has the length concatenated to 'abc'.
|
||||
testing "on abc including length" "cksum" "1219131554 3\n" "" 'abc'
|
||||
testing "on abc excluding length" "cksum -N" "1219131554\n" "" 'abc\x3'
|
||||
|
||||
# cksum on no contents gives 0xffffffff (=4294967295)
|
||||
testing "on no data post-inversion" "echo -n "" | cksum" "4294967295 0\n" "" ""
|
||||
# If we do preinversion we will then get 0.
|
||||
testing "on no data pre+post-inversion" "echo -n "" | cksum -P" "0 0\n" "" ""
|
||||
# If we skip the post-inversion we also get 0
|
||||
testing "on no data no inversion" "echo -n "" | cksum -I" "0 0\n" "" ""
|
||||
# Two wrongs make a right.
|
||||
testing "on no data pre-inversion" "echo -n "" | cksum -PI" "4294967295 0\n" "" ""
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
# TODO: coreutils cmp uses stdin if only one file is given
|
||||
testing "one argument match" 'cmp input && echo yes' "yes\n" \
|
||||
"one\ntwo\nthree" "one\ntwo\nthree"
|
||||
# posix says ""%s %s differ: char %d, line %d\n" but diffutils says "byte"
|
||||
testing "one argument diff" 'cmp input | sed s/byte/char/' \
|
||||
"input - differ: char 5, line 2\n" "one\ntwo\nthree" "one\nboing\nthree"
|
||||
|
||||
testing "missing file1 [fail]" 'cmp file1 input 2>/dev/null || echo $?' "2\n" "foo" ""
|
||||
|
||||
#mkdir dir
|
||||
#testing "directory [fail]" "cmp dir dir 2>/dev/null || echo yes" \
|
||||
#"yes\n" "" ""
|
||||
#rmdir dir
|
||||
|
||||
echo "ab
|
||||
c" > input2
|
||||
|
||||
testing "identical files, stdout" "cmp input input2" "" "ab\nc\n" ""
|
||||
testing "identical files, return code" "cmp input input2 && echo yes" "yes\n" "ab\nc\n" ""
|
||||
|
||||
testing "EOF, stderr" "cmp input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
|
||||
testing "EOF, return code" "cmp input input2 2>/dev/null || echo yes" "yes\n" "ab\nc\nx" ""
|
||||
# The gnu/dammit version fails this because posix says "char" and they don't.
|
||||
testing "diff, stdout" "cmp input input2 | sed s/byte/char/" \
|
||||
"input input2 differ: char 4, line 2\n" "ab\nx\nx" ""
|
||||
testing "diff, return code" "cmp input input2 > /dev/null || echo yes" "yes\n" "ab\nx\nx" ""
|
||||
|
||||
testing "-s EOF, return code" "cmp -s input input2 2>&1 || echo yes" "yes\n" "ab\nc\nx" ""
|
||||
testing "-s diff, return code" "cmp -s input input2 2>&1 || echo yes" "yes\n" "ab\nx\nx" ""
|
||||
|
||||
testing "-l EOF, stderr" "cmp -l input input2 2>&1" "cmp: EOF on input2\n" "ab\nc\nx" ""
|
||||
testing "-l diff and EOF, stdout and stderr" "cmp -l input input2 2>&1 | sort" "4 170 143\ncmp: EOF on input2\n" "ab\nx\nx" ""
|
||||
|
||||
testing "-s not exist" "cmp -s input doesnotexist 2>&1 || echo yes" "yes\n" "" ""
|
||||
|
||||
rm input2
|
||||
|
||||
testing "stdin and file" "cmp input - | sed s/byte/char/" \
|
||||
"input - differ: char 4, line 2\n" "ab\nc\n" "ab\nx\n"
|
||||
#testing "stdin and stdin" "cmp input -" "" "" "ab\nc\n"
|
||||
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
OLDUMASK=$(umask)
|
||||
umask 0002
|
||||
|
||||
# Create test file
|
||||
dd if=/dev/urandom of=random bs=64 count=1 2> /dev/null
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
testing "not enough arguments [fail]" "cp one 2>/dev/null || echo yes" \
|
||||
"yes\n" "" ""
|
||||
testing "-missing source [fail]" "cp missing two 2>/dev/null || echo yes" \
|
||||
"yes\n" "" ""
|
||||
testing "file->file" "cp random two && cmp random two && echo yes" \
|
||||
"yes\n" "" ""
|
||||
rm two
|
||||
|
||||
mkdir two
|
||||
testing "file->dir" "cp random two && cmp random two/random && echo yes" \
|
||||
"yes\n" "" ""
|
||||
rm two/random
|
||||
testing "file->dir/file" \
|
||||
"cp random two/random && cmp random two/random && echo yes" \
|
||||
"yes\n" "" ""
|
||||
testing "-r dir->missing" \
|
||||
"cp -r two three && cmp random three/random && echo yes" \
|
||||
"yes\n" "" ""
|
||||
touch walrus
|
||||
testing "-r dir->file [fail]" \
|
||||
"cp -r two walrus 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
touch two/three
|
||||
testing "-r dir hits file." \
|
||||
"cp -r three two 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
rm -rf two three walrus
|
||||
|
||||
touch two
|
||||
chmod 000 two
|
||||
skipnot [ $(id -u) -ne 0 ] # Root doesn't count.
|
||||
testing "file->inaccessible [fail]" \
|
||||
"cp random two 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
rm -f two
|
||||
|
||||
touch two
|
||||
chmod 000 two
|
||||
skipnot [ $(id -u) -ne 0 ] # Root doesn't count.
|
||||
testing "-f file->inaccessible" \
|
||||
"cp -f random two && cmp random two && echo yes" "yes\n" "" ""
|
||||
mkdir sub
|
||||
chmod 000 sub
|
||||
skipnot [ $(id -u) -ne 0 ] # Root doesn't count.
|
||||
testing "file->inaccessible_dir [fail]" \
|
||||
"cp random sub 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
rm two
|
||||
rmdir sub
|
||||
|
||||
# This test fails because our -rf deletes existing target files without
|
||||
# regard to what we'd be copying over it. Posix says to only do that if
|
||||
# we'd be copying a file over the file, but does not say _why_.
|
||||
|
||||
#mkdir dir
|
||||
#touch file
|
||||
#testing "-rf dir file [fail]" "cp -rf dir file 2>/dev/null || echo yes" \
|
||||
# "yes\n" "" ""
|
||||
#rm -rf dir file
|
||||
|
||||
touch one two
|
||||
testing "file1 file2 missing [fail]" \
|
||||
"cp one two missing 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
mkdir dir
|
||||
testing "dir file missing [fail]" \
|
||||
"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
testing "-rf dir file missing [fail]" \
|
||||
"cp dir two missing 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
testing "file1 file2 file [fail]" \
|
||||
"cp random one two 2>/dev/null || echo yes" "yes\n" "" ""
|
||||
testing "file1 file2 dir" \
|
||||
"cp random one dir && cmp random dir/random && cmp one dir/one && echo yes" \
|
||||
"yes\n" "" ""
|
||||
rm one two random
|
||||
rm -rf dir
|
||||
|
||||
mkdir -p one/two/three/four
|
||||
touch one/two/three/five
|
||||
touch one/{six,seven,eight}
|
||||
testing "-r /abspath dest" \
|
||||
"cp -r \"$(readlink -f one)\" dir && diff -r one dir && echo yes" \
|
||||
"yes\n" "" ""
|
||||
testing "-r dir again" "cp -r one/. dir && diff -r one dir && echo yes" \
|
||||
"yes\n" "" ""
|
||||
mkdir dir2
|
||||
testing "-r dir1/* dir2" \
|
||||
"cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" ""
|
||||
rm -rf one dir dir2
|
||||
|
||||
mkdir one; touch one/two; cp one/two one/three
|
||||
cp -pr one/ one_ # Succeeds twice in a row
|
||||
testing "-pr dir/." "cp -pr one/. one_ && echo yes" "yes\n" "" ""
|
||||
rm -rf one one_
|
||||
mkdir one; touch one/two; ln -s two one/three
|
||||
cp -pr one/ one_ # First time ok, second mustn't fail with "File exists"
|
||||
testing "-pr dir/. symlink child" "cp -pr one/. one_ && echo yes" "yes\n" "" ""
|
||||
rm -rf one one_
|
||||
|
||||
touch walrus
|
||||
chmod 644 walrus
|
||||
ln -s walrus woot
|
||||
testing "symlink dest permissions" "cp woot carpenter && stat -c %A carpenter" \
|
||||
"-rw-r--r--\n" "" ""
|
||||
testing "duplicated --preserve options" \
|
||||
"cp --preserve=mode,mode walrus walrus2 2>&1 || echo bad" "" "" ""
|
||||
rm -rf walrus woot carpenter
|
||||
|
||||
# cp -r ../source destdir
|
||||
# cp -r one/two/three missing
|
||||
# cp -r one/two/three two
|
||||
# cp file1 file2 dir
|
||||
# cp file1 missing file2 -> dir
|
||||
|
||||
# Make sure it's truncating existing file
|
||||
# copy with -d at top level, with -d in directory, without -d at top level,
|
||||
# without -d in directory
|
||||
|
||||
umask $OLDUMASK
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
# We need to test name and file padding.
|
||||
# This means all possible values of strlen(name)+1 % 4,
|
||||
# plus file sizes of at least 0-4.
|
||||
|
||||
touch a bb ccc dddd
|
||||
testing "name padding" "cpio -o -H newc|cpio -it" "a\nbb\nccc\ndddd\n" "" "a\nbb\nccc\ndddd\n"
|
||||
rm a bb ccc dddd
|
||||
|
||||
touch a
|
||||
printf '1' >b
|
||||
printf '22' >c
|
||||
printf '333' >d
|
||||
testing "file padding" "cpio -o -H newc|cpio -it" "a\nb\nc\nd\n" "" "a\nb\nc\nd\n"
|
||||
rm a b c d
|
||||
|
||||
touch a
|
||||
printf '1' >bb
|
||||
printf '22' >ccc
|
||||
printf '333' >dddd
|
||||
# With the proper padding, header length, and file length,
|
||||
# the relevant bit should be here:
|
||||
# 110*5 + 4*3 + 2 + 6*3 = 550 + 12 + 20 = 582
|
||||
# files are padded to n*4, names are padded to 2 + n*4 due to the header length
|
||||
testing "archive length" "cpio -o -H newc|dd ibs=2 skip=291 count=5 2>/dev/null" "TRAILER!!!" "" "a\nbb\nccc\ndddd\n"
|
||||
testing "archive magic" "cpio -o -H newc|dd ibs=2 count=3 2>/dev/null" "070701" "" "a\n"
|
||||
# check name length (8 bytes before the empty "crc")
|
||||
testing "name length" "cpio -o -H newc|dd ibs=2 skip=47 count=4 2>/dev/null" "00000002" "" "a\n"
|
||||
rm a bb ccc dddd
|
||||
|
||||
# archive dangling symlinks and empty files even if we cannot open them
|
||||
touch a; chmod a-rwx a; ln -s a/cant b
|
||||
testing "archives unreadable empty files" "cpio -o -H newc|cpio -it" "a\nb\n" "" "a\nb\n"
|
||||
chmod u+rw a; rm -f a b
|
||||
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2013 Robin Mittal <robinmittal.it@gmail.com>
|
||||
# Copyright 2013 Divya Kothari <divya.s.kothari@gmail.com>
|
||||
# Copyright 2013 Kyungwan.Han <asura321@gmail.com>
|
||||
|
||||
[ -f testing.sh ] && . testing.sh
|
||||
|
||||
#testing "name" "command" "result" "infile" "stdin"
|
||||
|
||||
# Creating test file for testing cut
|
||||
echo "one:two:three:four:five:six:seven
|
||||
alpha:beta:gamma:delta:epsilon:zeta:eta:theta:iota:kappa:lambda:mu
|
||||
the quick brown fox jumps over the lazy dog" >abc.txt
|
||||
|
||||
testing "-b a,a,a" "cut -b 3,3,3 abc.txt" "e\np\ne\n" "" ""
|
||||
testing "-b overlaps" "cut -b 1-3,2-5,7-9,9-10 abc.txt" \
|
||||
"one:to:th\nalphabeta\nthe qick \n" "" ""
|
||||
testing "-b encapsulated" "cut -b 3-8,4-6 abc.txt" "e:two:\npha:be\ne quic\n" \
|
||||
"" ""
|
||||
testing "-bO overlaps" \
|
||||
"cut --output-delimiter ' ' -b 1-3,2-5,7-9,9-10 abc.txt" \
|
||||
"one:t o:th\nalpha beta\nthe q ick \n" "" ""
|
||||
testing "high-low error" "cut -b 8-3 abc.txt 2>/dev/null || echo err" "err\n" \
|
||||
"" ""
|
||||
|
||||
testing "-c a-b" "cut -c 4-10 abc.txt" ":two:th\nha:beta\n quick \n" "" ""
|
||||
testing "-c a-" "cut -c 41- abc.txt" "\ntheta:iota:kappa:lambda:mu\ndog\n" "" ""
|
||||
testing "-c -b" "cut -c -39 abc.txt" \
|
||||
"one:two:three:four:five:six:seven\nalpha:beta:gamma:delta:epsilon:zeta:eta\nthe quick brown fox jumps over the lazy\n" \
|
||||
"" ""
|
||||
testing "-c a" "cut -c 40 abc.txt" "\n:\n \n" "" ""
|
||||
testing "-c a,b-c,d" "cut -c 3,5-7,10 abc.txt" "etwoh\npa:ba\nequi \n" "" ""
|
||||
toyonly testing "-c japan.txt" 'cut -c 3-6,9-12 "$FILES/utf8/japan.txt"' \
|
||||
"ガラスをられます\n" "" ""
|
||||
|
||||
# substitute for awk
|
||||
toyonly testcmd "-DF" "-DF 2,7,5" \
|
||||
"said and your\nare\nis demand. supply\nforecast :\nyou you better,\n\nEm: Took hate\n" "" \
|
||||
"Bother, said Pooh. It's your husband, and he has a gun.
|
||||
Cheerios are donut seeds.
|
||||
Talk is cheap because supply exceeds demand.
|
||||
Weather forecast for tonight : dark.
|
||||
Apple: you can buy better, but you can't pay more.
|
||||
Subcalifragilisticexpialidocious.
|
||||
Auntie Em: Hate you, hate Kansas. Took the dog. Dorothy."
|
||||
|
||||
testcmd "empty field" "-d ':' -f 1-3" "a::b\n" "" "a::b\n"
|
||||
testcmd "empty field 2" "-d ':' -f 3-5" "b::c\n" "" "a::b::c:d\n"
|
||||
|
||||
testing "-f a-" "cut -d ':' -f 5- abc.txt" "five:six:seven\nepsilon:zeta:eta:theta:iota:kappa:lambda:mu\nthe quick brown fox jumps over the lazy dog\n" "" ""
|
||||
|
||||
testing "show whole line with no delim" "cut -d ' ' -f 3 abc.txt" \
|
||||
"one:two:three:four:five:six:seven\nalpha:beta:gamma:delta:epsilon:zeta:eta:theta:iota:kappa:lambda:mu\nbrown\n" "" ""
|
||||
|
||||
testing "with echo, -c (a-b)" "echo 'ref_categorie=test' | cut -c 1-15 " "ref_categorie=t\n" "" ""
|
||||
testing "with echo, -c (a)" "echo 'ref_categorie=test' | cut -c 14" "=\n" "" ""
|
||||
|
||||
# Modifying abc.txt data as per new testcase
|
||||
echo "abcdefghijklmnopqrstuvwxyz" >abc.txt
|
||||
|
||||
testing "with -c (a,b,c)" "cut -c 4,5,20 abc.txt" "det\n" "" ""
|
||||
|
||||
testing "with -b (a,b,c)" "cut -b 4,5,20 abc.txt" "det\n" "" ""
|
||||
|
||||
# Modifying abc.txt data as per testcase
|
||||
echo "406378:Sales:Itorre:Jan
|
||||
031762:Marketing:Nasium:Jim
|
||||
636496:Research:Ancholie:Mel
|
||||
396082:Sales:Jucacion:Ed" >abc.txt
|
||||
|
||||
testing "with -d -f(:) -s" "cut -d: -f3 -s abc.txt" "Itorre\nNasium\nAncholie\nJucacion\n" "" ""
|
||||
|
||||
testing "with -d -f( ) -s" "cut -d' ' -f3 -s abc.txt && echo yes" "yes\n" "" ""
|
||||
|
||||
testing "with -d -f(a) -s" "cut -da -f3 -s abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
|
||||
|
||||
testing "with -d -f(a) -s -n" "cut -da -f3 -s -n abc.txt" "n\nsium:Jim\n\ncion:Ed\n" "" ""
|
||||
|
||||
# Removing abc.txt file for cleanup purpose
|
||||
rm abc.txt
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user