summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/coreutils
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/coreutils')
-rw-r--r--[-rwxr-xr-x]release/src/router/busybox/coreutils/Config.in669
-rw-r--r--release/src/router/busybox/coreutils/Kbuild95
-rw-r--r--release/src/router/busybox/coreutils/Makefile30
-rwxr-xr-xrelease/src/router/busybox/coreutils/Makefile.in92
-rw-r--r--release/src/router/busybox/coreutils/basename.c41
-rw-r--r--release/src/router/busybox/coreutils/cal.c201
-rw-r--r--release/src/router/busybox/coreutils/cat.c65
-rw-r--r--release/src/router/busybox/coreutils/catv.c75
-rw-r--r--release/src/router/busybox/coreutils/chgrp.c84
-rw-r--r--release/src/router/busybox/coreutils/chmod.c200
-rw-r--r--release/src/router/busybox/coreutils/chown.c229
-rw-r--r--release/src/router/busybox/coreutils/chroot.c36
-rw-r--r--release/src/router/busybox/coreutils/cksum.c67
-rw-r--r--release/src/router/busybox/coreutils/cmp.c152
-rw-r--r--release/src/router/busybox/coreutils/comm.c100
-rw-r--r--release/src/router/busybox/coreutils/cp.c167
-rw-r--r--release/src/router/busybox/coreutils/cut.c527
-rw-r--r--release/src/router/busybox/coreutils/date.c388
-rw-r--r--release/src/router/busybox/coreutils/dd.c438
-rw-r--r--release/src/router/busybox/coreutils/df.c224
-rw-r--r--release/src/router/busybox/coreutils/dirname.c28
-rw-r--r--release/src/router/busybox/coreutils/dos2unix.c230
-rw-r--r--release/src/router/busybox/coreutils/du.c261
-rw-r--r--release/src/router/busybox/coreutils/echo.c268
-rw-r--r--release/src/router/busybox/coreutils/env.c101
-rw-r--r--release/src/router/busybox/coreutils/expand.c180
-rw-r--r--release/src/router/busybox/coreutils/expr.c656
-rw-r--r--release/src/router/busybox/coreutils/false.c27
-rw-r--r--release/src/router/busybox/coreutils/fold.c229
-rw-r--r--release/src/router/busybox/coreutils/head.c120
-rw-r--r--release/src/router/busybox/coreutils/hostid.c28
-rw-r--r--release/src/router/busybox/coreutils/id.c270
-rwxr-xr-xrelease/src/router/busybox/coreutils/id_test.sh244
-rw-r--r--release/src/router/busybox/coreutils/install.c210
-rw-r--r--release/src/router/busybox/coreutils/length.c21
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/Kbuild12
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/Makefile30
-rwxr-xr-xrelease/src/router/busybox/coreutils/libcoreutils/Makefile.in32
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/coreutils.h18
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/cp_mv_stat.c17
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c29
-rw-r--r--release/src/router/busybox/coreutils/libcoreutils/xgetoptfile_sort_uniq.c38
-rw-r--r--release/src/router/busybox/coreutils/ln.c100
-rw-r--r--release/src/router/busybox/coreutils/logname.c36
-rw-r--r--release/src/router/busybox/coreutils/ls.c1348
-rw-r--r--release/src/router/busybox/coreutils/md5_sha1_sum.c192
-rw-r--r--release/src/router/busybox/coreutils/md5sum.c1102
-rw-r--r--release/src/router/busybox/coreutils/mkdir.c69
-rw-r--r--release/src/router/busybox/coreutils/mkfifo.c30
-rw-r--r--release/src/router/busybox/coreutils/mknod.c64
-rw-r--r--release/src/router/busybox/coreutils/mv.c154
-rw-r--r--release/src/router/busybox/coreutils/nice.c55
-rw-r--r--release/src/router/busybox/coreutils/nohup.c78
-rw-r--r--release/src/router/busybox/coreutils/od.c98
-rw-r--r--release/src/router/busybox/coreutils/od_bloaty.c1428
-rw-r--r--release/src/router/busybox/coreutils/printenv.c37
-rw-r--r--release/src/router/busybox/coreutils/printf.c656
-rw-r--r--release/src/router/busybox/coreutils/pwd.c30
-rw-r--r--release/src/router/busybox/coreutils/readlink.c72
-rw-r--r--release/src/router/busybox/coreutils/realpath.c44
-rw-r--r--release/src/router/busybox/coreutils/rm.c50
-rw-r--r--release/src/router/busybox/coreutils/rmdir.c69
-rw-r--r--release/src/router/busybox/coreutils/seq.c53
-rw-r--r--release/src/router/busybox/coreutils/sha1sum.c492
-rw-r--r--release/src/router/busybox/coreutils/sleep.c106
-rw-r--r--release/src/router/busybox/coreutils/sort.c438
-rw-r--r--release/src/router/busybox/coreutils/split.c139
-rw-r--r--release/src/router/busybox/coreutils/stat.c669
-rw-r--r--release/src/router/busybox/coreutils/stty.c2080
-rw-r--r--release/src/router/busybox/coreutils/sum.c99
-rw-r--r--release/src/router/busybox/coreutils/sync.c27
-rw-r--r--release/src/router/busybox/coreutils/tac.c106
-rw-r--r--release/src/router/busybox/coreutils/tail.c311
-rw-r--r--release/src/router/busybox/coreutils/tee.c135
-rw-r--r--release/src/router/busybox/coreutils/test.c968
-rw-r--r--release/src/router/busybox/coreutils/test_ptr_hack.c23
-rw-r--r--release/src/router/busybox/coreutils/touch.c91
-rw-r--r--release/src/router/busybox/coreutils/tr.c455
-rw-r--r--release/src/router/busybox/coreutils/true.c25
-rw-r--r--release/src/router/busybox/coreutils/tty.c46
-rw-r--r--release/src/router/busybox/coreutils/uname.c178
-rw-r--r--release/src/router/busybox/coreutils/uniq.c138
-rw-r--r--release/src/router/busybox/coreutils/usleep.c29
-rw-r--r--release/src/router/busybox/coreutils/uudecode.c545
-rw-r--r--release/src/router/busybox/coreutils/uuencode.c160
-rw-r--r--release/src/router/busybox/coreutils/watch.c110
-rw-r--r--release/src/router/busybox/coreutils/wc.c148
-rw-r--r--release/src/router/busybox/coreutils/who.c118
-rw-r--r--release/src/router/busybox/coreutils/whoami.c38
-rw-r--r--release/src/router/busybox/coreutils/yes.c44
90 files changed, 11432 insertions, 8980 deletions
diff --git a/release/src/router/busybox/coreutils/Config.in b/release/src/router/busybox/coreutils/Config.in
index 3f1e714e..b047ce5e 100755..100644
--- a/release/src/router/busybox/coreutils/Config.in
+++ b/release/src/router/busybox/coreutils/Config.in
@@ -5,560 +5,784 @@
menu "Coreutils"
-config CONFIG_BASENAME
+config BASENAME
bool "basename"
default n
help
basename is used to strip the directory and suffix from filenames,
- leaving just the filename itself. Enable this option if you wish
+ leaving just the filename itself. Enable this option if you wish
to enable the 'basename' utility.
-config CONFIG_CAL
+config CAL
bool "cal"
default n
help
- cal is used to display a montly calender.
+ cal is used to display a monthly calender.
-config CONFIG_CAT
+config CAT
bool "cat"
default n
help
cat is used to concatenate files and print them to the standard
- output. Enable this option if you wish to enable the 'cat' utility.
+ output. Enable this option if you wish to enable the 'cat' utility.
-config CONFIG_CHGRP
+config CATV
+ bool "catv"
+ default n
+ help
+ Display nonprinting characters as escape sequences (like some
+ implementations' cat -v option).
+
+config CHGRP
bool "chgrp"
default n
help
- chgrp is used to change the group owership of files.
+ chgrp is used to change the group ownership of files.
-config CONFIG_CHMOD
+config CHMOD
bool "chmod"
default n
help
chmod is used to change the access permission of files.
-config CONFIG_CHOWN
+config CHOWN
bool "chown"
default n
help
- chown is used too change the user and/or group ownership
+ chown is used to change the user and/or group ownership
of files.
-config CONFIG_CHROOT
+config CHROOT
bool "chroot"
default n
help
chroot is used to change the root directory and run a command.
The default command is `/bin/sh'.
-config CONFIG_CMP
- bool "cmp"
+config CKSUM
+ bool "cksum"
default n
help
- cmp is used to compare two files and returns the result
- to standard output.
+ cksum is used to calculate the CRC32 checksum of a file.
-config CONFIG_CP
+config COMM
+ bool "comm"
+ default n
+ help
+ comm is used to compare two files line by line and return
+ a three-column output.
+
+config CP
bool "cp"
default n
help
cp is used to copy files and directories.
-config CONFIG_CUT
+config CUT
bool "cut"
default n
help
cut is used to print selected parts of lines from
each file to stdout.
-if CONFIG_WATCH
- config CONFIG_DATE
- default y
- comment "date (forced enabled for use with watch)"
-endif
-
-if !CONFIG_WATCH
- config CONFIG_DATE
- bool "date"
- default n
- help
- date is used to set the system date or display the
- current time in the given format.
-endif
-
-config CONFIG_FEATURE_DATE_ISOFMT
- bool " Enable ISO date format output (-I)"
+config DATE
+ bool "date"
+ default n
+ help
+ date is used to set the system date or display the
+ current time in the given format.
+
+config FEATURE_DATE_ISOFMT
+ bool "Enable ISO date format output (-I)"
default y
- depends on CONFIG_DATE
+ depends on DATE
help
Enable option (-I) to output an ISO-8601 compliant
date/time string.
-config CONFIG_DD
+config DD
bool "dd"
default n
help
dd copies a file (from standard input to standard output,
by default) using specific input and output blocksizes,
- while optionally performing conversions on it.
+ while optionally performing conversions on it.
+
+config FEATURE_DD_SIGNAL_HANDLING
+ bool "Enable DD signal handling for status reporting"
+ default y
+ depends on DD
+ help
+ sending a SIGUSR1 signal to a running `dd' process makes it
+ print to standard error the number of records read and written
+ so far, then to resume copying.
+
+ $ dd if=/dev/zero of=/dev/null&
+ $ pid=$! kill -USR1 $pid; sleep 1; kill $pid
+ 10899206+0 records in 10899206+0 records out
+
+config FEATURE_DD_IBS_OBS
+ bool "Enable ibs, obs and conv options"
+ default n
+ depends on DD
+ help
+ Enables support for writing a certain number of bytes in and out,
+ at a time, and performing conversions on the data stream.
-config CONFIG_DF
+config DF
bool "df"
default n
help
df reports the amount of disk space used and available
on filesystems.
-config CONFIG_DIRNAME
+config FEATURE_DF_FANCY
+ bool "Enable -a, -i, -B"
+ default n
+ depends on DF
+ help
+ This option enables -a, -i and -B.
+
+config DIRNAME
bool "dirname"
default n
help
- dirname is used to strip a non directory suffix from
+ dirname is used to strip a non-directory suffix from
a file name.
-config CONFIG_DOS2UNIX
+config DOS2UNIX
bool "dos2unix/unix2dos"
default n
help
- dos2unix is uses to convert a text file from DOS format to
+ dos2unix is used to convert a text file from DOS format to
UNIX format, and vice versa.
-config CONFIG_UNIX2DOS
+config UNIX2DOS
bool
default y
- depends on CONFIG_DOS2UNIX
+ depends on DOS2UNIX
+ help
+ unix2dos is used to convert a text file from UNIX format to
+ DOS format, and vice versa.
-config CONFIG_DU
+config DU
bool "du (default blocksize of 512 bytes)"
default n
help
du is used to report the amount of disk space used
for specified files.
-config CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K
- bool " Use a default blocksize of 1024 bytes (1K)"
+config FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+ bool "Use a default blocksize of 1024 bytes (1K)"
default y
- depends on CONFIG_DU
+ depends on DU
help
Use a blocksize of (1K) instead of the default 512b.
-config CONFIG_ECHO
- bool "echo (basic SUSv3 version taking no options"
+config ECHO
+ bool "echo (basic SuSv3 version taking no options)"
default n
help
echo is used to print a specified string to stdout.
-config CONFIG_FEATURE_FANCY_ECHO
- bool " Enable echo options (-n and -e)"
+# this entry also appears in shell/Config.in, next to the echo builtin
+config FEATURE_FANCY_ECHO
+ bool "Enable echo options (-n and -e)"
default y
- depends on CONFIG_ECHO
+ depends on ECHO || ASH_BUILTIN_ECHO || HUSH
help
- This adds options (-n and -e) to echo.
+ This adds options (-n and -e) to echo.
-config CONFIG_ENV
+config ENV
bool "env"
default n
help
env is used to set an environment variable and run
- a command, without options it displays the current
+ a command; without options it displays the current
environment.
-config CONFIG_EXPR
+config FEATURE_ENV_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on ENV && GETOPT_LONG
+ help
+ Support long options for the env applet.
+
+config EXPAND
+ bool "expand"
+ default n
+ help
+ By default, convert all tabs to spaces.
+
+config FEATURE_EXPAND_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on EXPAND && GETOPT_LONG
+ help
+ Support long options for the expand applet.
+
+config EXPR
bool "expr"
default n
help
expr is used to calculate numbers and print the result
to standard output.
-if CONFIG_HUSH || CONFIG_LASH || CONFIG_MSH
- config CONFIG_FALSE
- default y
- comment "false (forced enabled for use with shell)"
-endif
-
-if !CONFIG_HUSH && !CONFIG_LASH && !CONFIG_MSH
- config CONFIG_FALSE
- bool "false"
- default n
- help
- false returns an exit code of FALSE (1).
-endif
-
-config CONFIG_FOLD
+config EXPR_MATH_SUPPORT_64
+ bool "Extend Posix numbers support to 64 bit"
+ default n
+ depends on EXPR
+ help
+ Enable 64-bit math support in the expr applet. This will make
+ the applet slightly larger, but will allow computation with very
+ large numbers.
+
+config FALSE
+ bool "false"
+ default n
+ help
+ false returns an exit code of FALSE (1).
+
+config FOLD
bool "fold"
default n
help
Wrap text to fit a specific width.
-config CONFIG_HEAD
+config HEAD
bool "head"
default n
help
head is used to print the first specified number of lines
from files.
-config CONFIG_FEATURE_FANCY_HEAD
- bool " Enable head options (-c, -q, and -v)"
+config FEATURE_FANCY_HEAD
+ bool "Enable head options (-c, -q, and -v)"
default n
- depends on CONFIG_HEAD
+ depends on HEAD
help
This enables the head options (-c, -q, and -v).
-config CONFIG_HOSTID
+config HOSTID
bool "hostid"
default n
help
hostid prints the numeric identifier (in hexadecimal) for
the current host.
-config CONFIG_ID
+config ID
bool "id"
default n
help
id displays the current user and group ID names.
-config CONFIG_LENGTH
+config INSTALL
+ bool "install"
+ default n
+ help
+ Copy files and set attributes.
+
+config FEATURE_INSTALL_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on INSTALL && GETOPT_LONG
+ help
+ Support long options for the install applet.
+
+config LENGTH
bool "length"
default n
help
length is used to print out the length of a specified string.
-config CONFIG_LN
+config LN
bool "ln"
default n
help
ln is used to create hard or soft links between files.
-config CONFIG_LOGNAME
+config LOGNAME
bool "logname"
default n
help
logname is used to print the current user's login name.
-config CONFIG_LS
+config LS
bool "ls"
default n
help
ls is used to list the contents of directories.
-config CONFIG_FEATURE_LS_FILETYPES
- bool " Enable filetyping options (-p and -F)"
+config FEATURE_LS_FILETYPES
+ bool "Enable filetyping options (-p and -F)"
default y
- depends on CONFIG_LS
+ depends on LS
help
Enable the ls options (-p and -F).
-config CONFIG_FEATURE_LS_FOLLOWLINKS
- bool " Enable symlinks dereferencing (-L)"
+config FEATURE_LS_FOLLOWLINKS
+ bool "Enable symlinks dereferencing (-L)"
default y
- depends on CONFIG_LS
+ depends on LS
help
Enable the ls option (-L).
-config CONFIG_FEATURE_LS_RECURSIVE
- bool " Enable recursion (-R)"
+config FEATURE_LS_RECURSIVE
+ bool "Enable recursion (-R)"
default y
- depends on CONFIG_LS
+ depends on LS
help
Enable the ls option (-R).
-config CONFIG_FEATURE_LS_SORTFILES
- bool " Sort the file names"
+config FEATURE_LS_SORTFILES
+ bool "Sort the file names"
default y
- depends on CONFIG_LS
+ depends on LS
help
Allow ls to sort file names alphabetically.
-config CONFIG_FEATURE_LS_TIMESTAMPS
- bool " Show file timestamps"
+config FEATURE_LS_TIMESTAMPS
+ bool "Show file timestamps"
default y
- depends on CONFIG_LS
+ depends on LS
help
Allow ls to display timestamps for files.
-config CONFIG_FEATURE_LS_USERNAME
- bool " Show username/groupnames"
+config FEATURE_LS_USERNAME
+ bool "Show username/groupnames"
default y
- depends on CONFIG_LS
+ depends on LS
help
Allow ls to display username/groupname for files.
-config CONFIG_FEATURE_LS_COLOR
- bool " Use color to identify file types"
+config FEATURE_LS_COLOR
+ bool "Allow use of color to identify file types"
default y
- depends on CONFIG_LS
+ depends on LS && GETOPT_LONG
+ help
+ This enables the --color option to ls.
+
+config FEATURE_LS_COLOR_IS_DEFAULT
+ bool "Produce colored ls output by default"
+ default n
+ depends on FEATURE_LS_COLOR
help
- Allow ls to use color when displaying files.
+ Saying yes here will turn coloring on by default,
+ even if no "--color" option is given to the ls command.
+ This is not recommended, since the colors are not
+ configurable, and the output may not be legible on
+ many output screens.
-config CONFIG_MD5SUM
+config MD5SUM
bool "md5sum"
default n
help
md5sum is used to print or check MD5 checksums.
-config CONFIG_MKDIR
+config MKDIR
bool "mkdir"
default n
help
mkdir is used to create directories with the specified names.
-config CONFIG_MKFIFO
+config FEATURE_MKDIR_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on MKDIR && GETOPT_LONG
+ help
+ Support long options for the mkdir applet.
+
+config MKFIFO
bool "mkfifo"
default n
help
mkfifo is used to create FIFOs (named pipes).
The `mknod' program can also create FIFOs.
-config CONFIG_MKNOD
+config MKNOD
bool "mknod"
default n
help
mknod is used to create FIFOs or block/character special
files with the specified names.
-config CONFIG_MV
+config MV
bool "mv"
default n
help
mv is used to move or rename files or directories.
-config CONFIG_OD
+config FEATURE_MV_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on MV && GETOPT_LONG
+ help
+ Support long options for the mv applet.
+
+config NICE
+ bool "nice"
+ default n
+ help
+ nice runs a program with modified scheduling priority.
+
+config NOHUP
+ bool "nohup"
+ default n
+ help
+ run a command immune to hangups, with output to a non-tty.
+
+config OD
bool "od"
default n
help
od is used to dump binary files in octal and other formats.
-config CONFIG_PRINTF
+config PRINTENV
+ bool "printenv"
+ default n
+ help
+ printenv is used to print all or part of environment.
+
+config PRINTF
bool "printf"
default n
help
printf is used to format and print specified strings.
It's similar to `echo' except it has more options.
-config CONFIG_PWD
+config PWD
bool "pwd"
default n
help
pwd is used to print the current directory.
-config CONFIG_REALPATH
+config READLINK
+ bool "readlink"
+ default n
+ help
+ This program reads a symbolic link and returns the name
+ of the file it points to
+
+config FEATURE_READLINK_FOLLOW
+ bool "Enable canonicalization by following all symlinks (-f)"
+ default n
+ depends on READLINK
+ help
+ Enable the readlink option (-f).
+
+config REALPATH
bool "realpath"
default n
help
Return the canonicalized absolute pathname.
- This isnt provided by GNU shellutils, but where else does it belong.
+ This isn't provided by GNU shellutils, but where else does it belong.
-config CONFIG_RM
+config RM
bool "rm"
default n
help
rm is used to remove files or directories.
-config CONFIG_RMDIR
+config RMDIR
bool "rmdir"
default n
help
rmdir is used to remove empty directories.
-config CONFIG_SHA1SUM
+config FEATURE_RMDIR_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on RMDIR && GETOPT_LONG
+ help
+ Support long options for the rmdir applet, including
+ --ignore-fail-on-non-empty for compatibility with GNU rmdir.
+
+config SEQ
+ bool "seq"
+ default n
+ help
+ print a sequence of numbers
+
+config SHA1SUM
bool "sha1sum"
default n
help
Compute and check SHA1 message digest
-config CONFIG_FEATURE_SHA1SUM_CHECK
- bool " Enale -c and -w options"
+config SHA256SUM
+ bool "sha256sum"
default n
help
- Enabling the -c and -w options allow files to be checked
- against pre-calculated hash values.
+ Compute and check SHA256 message digest
+
+config SHA512SUM
+ bool "sha512sum"
+ default n
+ help
+ Compute and check SHA512 message digest
-config CONFIG_SLEEP
- bool "sleep (single integer arg with no suffix)"
+config SLEEP
+ bool "sleep"
default n
help
- sleep is used to pause for a specified number of seconds,
+ sleep is used to pause for a specified number of seconds.
+ It comes in 3 versions:
+ - small: takes one integer parameter
+ - fancy: takes multiple integer arguments with suffixes:
+ sleep 1d 2h 3m 15s
+ - fancy with fractional numbers:
+ sleep 2.3s 4.5h sleeps for 16202.3 seconds
+ Last one is "the most compatible" with coreutils sleep,
+ but it adds around 1k of code.
-config CONFIG_FEATURE_FANCY_SLEEP
- bool " Enable multiple integer args and optional time suffixes"
+config FEATURE_FANCY_SLEEP
+ bool "Enable multiple arguments and s/m/h/d suffixes"
default n
- depends on CONFIG_SLEEP
+ depends on SLEEP
help
Allow sleep to pause for specified minutes, hours, and days.
-config CONFIG_SORT
+config FEATURE_FLOAT_SLEEP
+ bool "Enable fractional arguments"
+ default n
+ depends on FEATURE_FANCY_SLEEP
+ help
+ Allow for fractional numeric parameters.
+
+config SORT
bool "sort"
default n
help
sort is used to sort lines of text in specified files.
-config CONFIG_FEATURE_SORT_REVERSE
- bool " Enable reverse sort"
+config FEATURE_SORT_BIG
+ bool "Full SuSv3 compliant sort (support -ktcsbdfiozgM)"
default y
- depends on CONFIG_SORT
+ depends on SORT
help
- Enable the `-r' option that allows sort to sort lines of
- text in reverse.
+ Without this, sort only supports -r, -u, and an integer version
+ of -n. Selecting this adds sort keys, floating point support, and
+ more. This adds a little over 3k to a nonstatic build on x86.
-config CONFIG_FEATURE_SORT_UNIQUE
- bool " Enable unique sort"
- default y
- depends on CONFIG_SORT
+ The SuSv3 sort standard is available at:
+ http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
+
+config SPLIT
+ bool "split"
+ default n
+ help
+ split a file into pieces.
+
+config FEATURE_SPLIT_FANCY
+ bool "Fancy extensions"
+ default n
+ depends on SPLIT
+ help
+ Add support for features not required by SUSv3.
+ Supports additional suffixes 'b' for 512 bytes,
+ 'g' for 1GiB for the -b option.
+
+config STAT
+ bool "stat"
+ default n
help
- Enable the `-u' option that allows sort to only sort lines
- that are uniq.
+ display file or filesystem status.
-config CONFIG_STTY
+config FEATURE_STAT_FORMAT
+ bool "Enable custom formats (-c)"
+ default n
+ depends on STAT
+ help
+ Without this, stat will not support the '-c format' option where
+ users can pass a custom format string for output. This adds about
+ 7k to a nonstatic build on amd64.
+
+config STTY
bool "stty"
default n
help
stty is used to change and print terminal line settings.
-config CONFIG_SYNC
+config SUM
+ bool "sum"
+ default n
+ help
+ checksum and count the blocks in a file
+
+config SYNC
bool "sync"
default n
help
sync is used to flush filesystem buffers.
-config CONFIG_TAIL
+config TAC
+ bool "tac"
+ default n
+ help
+ tac is used to concatenate and print files in reverse.
+
+config TAIL
bool "tail"
default n
help
tail is used to print the last specified number of lines
from files.
-config CONFIG_FEATURE_FANCY_TAIL
- bool " Enable extra tail options (-c, -q, -s, and -v)"
+config FEATURE_FANCY_TAIL
+ bool "Enable extra tail options (-q, -s, and -v)"
default y
- depends on CONFIG_TAIL
+ depends on TAIL
help
- Enable tail options (-c, -q, -s, and -v).
+ The options (-q, -s, and -v) are provided by GNU tail, but
+ are not specific in the SUSv3 standard.
-config CONFIG_TEE
+config TEE
bool "tee"
default n
help
tee is used to read from standard input and write
to standard output and files.
-config CONFIG_FEATURE_TEE_USE_BLOCK_IO
- bool " Enable block i/o (larger/faster) instead of byte i/o."
+config FEATURE_TEE_USE_BLOCK_IO
+ bool "Enable block I/O (larger/faster) instead of byte I/O"
default n
- depends on CONFIG_TEE
+ depends on TEE
help
Enable this option for a faster tee, at expense of size.
-if CONFIG_ASH || CONFIG_HUSH || CONFIG_LASH || CONFIG_MSH
- config CONFIG_TEST
- default y
- comment "test (forced enabled for use with shell)"
-endif
-
-if !CONFIG_ASH && !CONFIG_HUSH && !CONFIG_LASH && !CONFIG_MSH
- config CONFIG_TEST
- bool "test"
- default n
- help
- test is used to check file types and compare values,
- returning an appropriate exit code. The shells (ash
- and bash have test builtin).
-endif
-
-config CONFIG_TOUCH
+config TEST
+ bool "test"
+ default n
+ help
+ test is used to check file types and compare values,
+ returning an appropriate exit code. The bash shell
+ has test built in, ash can build it in optionally.
+
+config FEATURE_TEST_64
+ bool "Extend test to 64 bit"
+ default n
+ depends on TEST || ASH_BUILTIN_TEST
+ help
+ Enable 64-bit support in test.
+
+config TOUCH
bool "touch"
default n
help
touch is used to create or change the access and/or
modification timestamp of specified files.
-config CONFIG_TR
+config TR
bool "tr"
default n
help
tr is used to squeeze, and/or delete characters from standard
input, writing to standard output.
-if CONFIG_HUSH || CONFIG_LASH || CONFIG_MSH
- config CONFIG_TRUE
- default y
- comment "true (forced enabled for use with shell)"
-endif
+config FEATURE_TR_CLASSES
+ bool "Enable character classes (such as [:upper:])"
+ default n
+ depends on TR
+ help
+ Enable character classes, enabling commands such as:
+ tr [:upper:] [:lower:] to convert input into lowercase.
-if !CONFIG_HUSH && !CONFIG_LASH && !CONFIG_MSH
- config CONFIG_TRUE
- bool "true"
- default n
- help
- true returns an exit code of TRUE (0).
+config FEATURE_TR_EQUIV
+ bool "Enable equivalence classes"
+ default n
+ depends on TR
+ help
+ Enable equivalence classes, which essentially add the enclosed
+ character to the current set. For instance, tr [=a=] xyz would
+ replace all instances of 'a' with 'xyz'. This option is mainly
+ useful for cases when no other way of expressing a character
+ is possible.
-endif
+config TRUE
+ bool "true"
+ default n
+ help
+ true returns an exit code of TRUE (0).
-config CONFIG_TTY
+config TTY
bool "tty"
default n
help
tty is used to print the name of the current terminal to
standard output.
-config CONFIG_UNAME
+config UNAME
bool "uname"
default n
help
uname is used to print system information.
-config CONFIG_UNIQ
+config UNEXPAND
+ bool "unexpand"
+ default n
+ help
+ By default, convert only leading sequences of blanks to tabs.
+
+config FEATURE_UNEXPAND_LONG_OPTIONS
+ bool "Enable long options"
+ default n
+ depends on UNEXPAND && GETOPT_LONG
+ help
+ Support long options for the unexpand applet.
+
+config UNIQ
bool "uniq"
default n
help
uniq is used to remove duplicate lines from a sorted file.
-config CONFIG_USLEEP
+config USLEEP
bool "usleep"
default n
help
usleep is used to pause for a specified number of microseconds.
-config CONFIG_UUDECODE
+config UUDECODE
bool "uudecode"
default n
help
uudecode is used to decode a uuencoded file.
-config CONFIG_UUENCODE
+config UUENCODE
bool "uuencode"
default n
help
uuencode is used to uuencode a file.
-config CONFIG_WATCH
- bool "watch"
- default n
- help
- watch is used to execute a program periodically, showing
- output to the screen.
-
-config CONFIG_WC
+config WC
bool "wc"
default n
help
wc is used to print the number of bytes, words, and lines,
in specified files.
-config CONFIG_WHO
+config FEATURE_WC_LARGE
+ bool "Support very large files in wc"
+ default n
+ depends on WC
+ help
+ Use "unsigned long long" in wc for counter variables.
+
+config WHO
bool "who"
default n
+ select FEATURE_UTMP
help
who is used to show who is logged on.
-config CONFIG_WHOAMI
+config WHOAMI
bool "whoami"
default n
help
whoami is used to print the username of the current
user id (same as id -un).
-config CONFIG_YES
+config YES
bool "yes"
default n
help
@@ -566,37 +790,50 @@ config CONFIG_YES
the default string `y'.
comment "Common options for cp and mv"
- depends on CONFIG_CP || CONFIG_MV
+ depends on CP || MV
-config CONFIG_FEATURE_PRESERVE_HARDLINKS
- bool " Preserve hard links"
+config FEATURE_PRESERVE_HARDLINKS
+ bool "Preserve hard links"
default n
- depends on CONFIG_CP || CONFIG_MV
+ depends on CP || MV
help
Allow cp and mv to preserve hard links.
-comment "Common options for ls and more"
- depends on CONFIG_LS || CONFIG_MORE
+comment "Common options for ls, more and telnet"
+ depends on LS || MORE || TELNET
-config CONFIG_FEATURE_AUTOWIDTH
- bool " Calculate terminal & column widths"
+config FEATURE_AUTOWIDTH
+ bool "Calculate terminal & column widths"
default y
- depends on CONFIG_LS || CONFIG_MORE
+ depends on LS || MORE || TELNET
help
- This option allows utilities such as 'ls' and 'more' to determine the
- width of the screen, which can allow them to display additional text
- or avoid wrapping text onto the next line. If you leave this
- disabled, your utilities will be especially primitive and will be
- unable to determine the current screen width.
+ This option allows utilities such as 'ls', 'more' and 'telnet'
+ to determine the width of the screen, which can allow them to
+ display additional text or avoid wrapping text onto the next line.
+ If you leave this disabled, your utilities will be especially
+ primitive and will be unable to determine the current screen width.
comment "Common options for df, du, ls"
- depends on CONFIG_DF || CONFIG_DU || CONFIG_LS
+ depends on DF || DU || LS
-config CONFIG_FEATURE_HUMAN_READABLE
- bool " Support for human readable output (example 13k, 23M, 235G)"
+config FEATURE_HUMAN_READABLE
+ bool "Support for human readable output (example 13k, 23M, 235G)"
default n
- depends on CONFIG_DF || CONFIG_DU || CONFIG_LS
+ depends on DF || DU || LS
help
Allow df, du, and ls to have human readable output.
+comment "Common options for md5sum, sha1sum"
+ depends on MD5SUM || SHA1SUM
+
+config FEATURE_MD5_SHA1_SUM_CHECK
+ bool "Enable -c, -s and -w options"
+ default n
+ depends on MD5SUM || SHA1SUM
+ help
+ Enabling the -c options allows files to be checked
+ against pre-calculated hash values.
+
+ -s and -w are useful options when verifying checksums.
+
endmenu
diff --git a/release/src/router/busybox/coreutils/Kbuild b/release/src/router/busybox/coreutils/Kbuild
new file mode 100644
index 00000000..57100a9c
--- /dev/null
+++ b/release/src/router/busybox/coreutils/Kbuild
@@ -0,0 +1,95 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+libs-y += libcoreutils/
+
+lib-y:=
+lib-$(CONFIG_BASENAME) += basename.o
+lib-$(CONFIG_CAL) += cal.o
+lib-$(CONFIG_CAT) += cat.o
+lib-$(CONFIG_MORE) += cat.o # more uses it if stdout isn't a tty
+lib-$(CONFIG_LESS) += cat.o # less too
+lib-$(CONFIG_CRONTAB) += cat.o # crontab -l
+lib-$(CONFIG_CATV) += catv.o
+lib-$(CONFIG_CHGRP) += chgrp.o chown.o
+lib-$(CONFIG_CHMOD) += chmod.o
+lib-$(CONFIG_CHOWN) += chown.o
+lib-$(CONFIG_CHROOT) += chroot.o
+lib-$(CONFIG_CKSUM) += cksum.o
+lib-$(CONFIG_COMM) += comm.o
+lib-$(CONFIG_CP) += cp.o
+lib-$(CONFIG_CUT) += cut.o
+lib-$(CONFIG_DATE) += date.o
+lib-$(CONFIG_DD) += dd.o
+lib-$(CONFIG_DF) += df.o
+lib-$(CONFIG_DIRNAME) += dirname.o
+lib-$(CONFIG_DOS2UNIX) += dos2unix.o
+lib-$(CONFIG_DU) += du.o
+lib-$(CONFIG_ECHO) += echo.o
+lib-$(CONFIG_ASH) += echo.o # used by ash
+lib-$(CONFIG_HUSH) += echo.o # used by hush
+lib-$(CONFIG_ENV) += env.o
+lib-$(CONFIG_EXPR) += expr.o
+lib-$(CONFIG_EXPAND) += expand.o
+lib-$(CONFIG_FALSE) += false.o
+lib-$(CONFIG_FOLD) += fold.o
+lib-$(CONFIG_HEAD) += head.o
+lib-$(CONFIG_HOSTID) += hostid.o
+lib-$(CONFIG_ID) += id.o
+lib-$(CONFIG_INSTALL) += install.o
+lib-$(CONFIG_LENGTH) += length.o
+lib-$(CONFIG_LN) += ln.o
+lib-$(CONFIG_LOGNAME) += logname.o
+lib-$(CONFIG_LS) += ls.o
+lib-$(CONFIG_FTPD) += ls.o
+lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o
+lib-$(CONFIG_MKDIR) += mkdir.o
+lib-$(CONFIG_MKFIFO) += mkfifo.o
+lib-$(CONFIG_MKNOD) += mknod.o
+lib-$(CONFIG_MV) += mv.o
+lib-$(CONFIG_NICE) += nice.o
+lib-$(CONFIG_NOHUP) += nohup.o
+lib-$(CONFIG_OD) += od.o
+lib-$(CONFIG_PRINTENV) += printenv.o
+lib-$(CONFIG_PRINTF) += printf.o
+lib-$(CONFIG_ASH_BUILTIN_PRINTF) += printf.o
+lib-$(CONFIG_PWD) += pwd.o
+lib-$(CONFIG_READLINK) += readlink.o
+lib-$(CONFIG_REALPATH) += realpath.o
+lib-$(CONFIG_RM) += rm.o
+lib-$(CONFIG_RMDIR) += rmdir.o
+lib-$(CONFIG_SEQ) += seq.o
+lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o
+lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o
+lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o
+lib-$(CONFIG_SLEEP) += sleep.o
+lib-$(CONFIG_SPLIT) += split.o
+lib-$(CONFIG_SORT) += sort.o
+lib-$(CONFIG_STAT) += stat.o
+lib-$(CONFIG_STTY) += stty.o
+lib-$(CONFIG_SUM) += sum.o
+lib-$(CONFIG_SYNC) += sync.o
+lib-$(CONFIG_TAC) += tac.o
+lib-$(CONFIG_TAIL) += tail.o
+lib-$(CONFIG_TEE) += tee.o
+lib-$(CONFIG_TEST) += test.o test_ptr_hack.o
+lib-$(CONFIG_ASH) += test.o test_ptr_hack.o # used by ash
+lib-$(CONFIG_HUSH) += test.o test_ptr_hack.o # used by hush
+lib-$(CONFIG_MSH) += test.o test_ptr_hack.o # used by msh
+lib-$(CONFIG_TOUCH) += touch.o
+lib-$(CONFIG_TR) += tr.o
+lib-$(CONFIG_TRUE) += true.o
+lib-$(CONFIG_TTY) += tty.o
+lib-$(CONFIG_UNAME) += uname.o
+lib-$(CONFIG_UNEXPAND) += expand.o
+lib-$(CONFIG_UNIQ) += uniq.o
+lib-$(CONFIG_USLEEP) += usleep.o
+lib-$(CONFIG_UUDECODE) += uudecode.o
+lib-$(CONFIG_UUENCODE) += uuencode.o
+lib-$(CONFIG_WC) += wc.o
+lib-$(CONFIG_WHO) += who.o
+lib-$(CONFIG_WHOAMI) += whoami.o
+lib-$(CONFIG_YES) += yes.o
diff --git a/release/src/router/busybox/coreutils/Makefile b/release/src/router/busybox/coreutils/Makefile
deleted file mode 100644
index a5cdf624..00000000
--- a/release/src/router/busybox/coreutils/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-TOPDIR:= ../
-SHELLUTILS_DIR:=./
-include $(TOPDIR).config
-include $(TOPDIR)Rules.mak
-include Makefile.in
-all: $(libraries-y)
--include $(TOPDIR).depend
-
-clean:
- rm -f *.o *.a $(AR_TARGET)
-
diff --git a/release/src/router/busybox/coreutils/Makefile.in b/release/src/router/busybox/coreutils/Makefile.in
deleted file mode 100755
index 95eda1ac..00000000
--- a/release/src/router/busybox/coreutils/Makefile.in
+++ /dev/null
@@ -1,92 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-COREUTILS_AR:=coreutils.a
-ifndef $(COREUTILS_DIR)
-COREUTILS_DIR:=$(TOPDIR)coreutils/
-endif
-
-COREUTILS-y:=
-COREUTILS-$(CONFIG_BASENAME) += basename.o
-COREUTILS-$(CONFIG_CAL) += cal.o
-COREUTILS-$(CONFIG_CAT) += cat.o
-COREUTILS-$(CONFIG_CHGRP) += chgrp.o
-COREUTILS-$(CONFIG_CHMOD) += chmod.o
-COREUTILS-$(CONFIG_CHOWN) += chown.o
-COREUTILS-$(CONFIG_CHROOT) += chroot.o
-COREUTILS-$(CONFIG_CMP) += cmp.o
-COREUTILS-$(CONFIG_CP) += cp.o
-COREUTILS-$(CONFIG_CUT) += cut.o
-COREUTILS-$(CONFIG_DATE) += date.o
-COREUTILS-$(CONFIG_DD) += dd.o
-COREUTILS-$(CONFIG_DF) += df.o
-COREUTILS-$(CONFIG_DIRNAME) += dirname.o
-COREUTILS-$(CONFIG_DOS2UNIX) += dos2unix.o
-COREUTILS-$(CONFIG_DU) += du.o
-COREUTILS-$(CONFIG_ECHO) += echo.o
-COREUTILS-$(CONFIG_ENV) += env.o
-COREUTILS-$(CONFIG_EXPR) += expr.o
-COREUTILS-$(CONFIG_FALSE) += false.o
-COREUTILS-$(CONFIG_FOLD) += fold.o
-COREUTILS-$(CONFIG_HEAD) += head.o
-COREUTILS-$(CONFIG_HOSTID) += hostid.o
-COREUTILS-$(CONFIG_ID) += id.o
-COREUTILS-$(CONFIG_LENGTH) += length.o
-COREUTILS-$(CONFIG_LN) += ln.o
-COREUTILS-$(CONFIG_LOGNAME) += logname.o
-COREUTILS-$(CONFIG_LS) += ls.o
-COREUTILS-$(CONFIG_MD5SUM) += md5sum.o
-COREUTILS-$(CONFIG_MKDIR) += mkdir.o
-COREUTILS-$(CONFIG_MKFIFO) += mkfifo.o
-COREUTILS-$(CONFIG_MKNOD) += mknod.o
-COREUTILS-$(CONFIG_MV) += mv.o
-COREUTILS-$(CONFIG_OD) += od.o
-COREUTILS-$(CONFIG_PRINTF) += printf.o
-COREUTILS-$(CONFIG_PWD) += pwd.o
-COREUTILS-$(CONFIG_REALPATH) += realpath.o
-COREUTILS-$(CONFIG_RM) += rm.o
-COREUTILS-$(CONFIG_RMDIR) += rmdir.o
-COREUTILS-$(CONFIG_SHA1SUM) += sha1sum.o
-COREUTILS-$(CONFIG_SLEEP) += sleep.o
-COREUTILS-$(CONFIG_SORT) += sort.o
-COREUTILS-$(CONFIG_STTY) += stty.o
-COREUTILS-$(CONFIG_SYNC) += sync.o
-COREUTILS-$(CONFIG_TAIL) += tail.o
-COREUTILS-$(CONFIG_TEE) += tee.o
-COREUTILS-$(CONFIG_TEST) += test.o
-COREUTILS-$(CONFIG_TOUCH) += touch.o
-COREUTILS-$(CONFIG_TR) += tr.o
-COREUTILS-$(CONFIG_TRUE) += true.o
-COREUTILS-$(CONFIG_TTY) += tty.o
-COREUTILS-$(CONFIG_UNAME) += uname.o
-COREUTILS-$(CONFIG_UNIQ) += uniq.o
-COREUTILS-$(CONFIG_USLEEP) += usleep.o
-COREUTILS-$(CONFIG_UUDECODE) += uudecode.o
-COREUTILS-$(CONFIG_UUENCODE) += uuencode.o
-COREUTILS-$(CONFIG_WATCH) += watch.o
-COREUTILS-$(CONFIG_WC) += wc.o
-COREUTILS-$(CONFIG_WHO) += who.o
-COREUTILS-$(CONFIG_WHOAMI) += whoami.o
-COREUTILS-$(CONFIG_YES) += yes.o
-
-libraries-y+=$(COREUTILS_DIR)$(COREUTILS_AR)
-
-$(COREUTILS_DIR)$(COREUTILS_AR): $(patsubst %,$(COREUTILS_DIR)%, $(COREUTILS-y))
- $(AR) -ro $@ $(patsubst %,$(COREUTILS_DIR)%, $(COREUTILS-y))
-
diff --git a/release/src/router/busybox/coreutils/basename.c b/release/src/router/busybox/coreutils/basename.c
index 7fcdb836..8a5597e6 100644
--- a/release/src/router/busybox/coreutils/basename.c
+++ b/release/src/router/busybox/coreutils/basename.c
@@ -2,21 +2,9 @@
/*
* Mini basename implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
*/
@@ -32,12 +20,12 @@
* 3) Save some space by using strcmp(). Calling strncmp() here was silly.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "busybox.h"
+#include "libbb.h"
-extern int basename_main(int argc, char **argv)
+/* This is a NOFORK applet. Be very careful! */
+
+int basename_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int basename_main(int argc, char **argv)
{
size_t m, n;
char *s;
@@ -46,17 +34,20 @@ extern int basename_main(int argc, char **argv)
bb_show_usage();
}
- s = bb_get_last_path_component(*++argv);
+ /* It should strip slash: /abc/def/ -> def */
+ s = bb_get_last_path_component_strip(*++argv);
+ m = strlen(s);
if (*++argv) {
n = strlen(*argv);
- m = strlen(s);
if ((m > n) && ((strcmp)(s+m-n, *argv) == 0)) {
- s[m-n] = '\0';
+ m -= n;
+ /*s[m] = '\0'; - redundant */
}
}
- puts(s);
-
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ /* puts(s) will do, but we can do without stdio this way: */
+ s[m++] = '\n';
+ /* NB: != is correct here: */
+ return full_write(STDOUT_FILENO, s, m) != (ssize_t)m;
}
diff --git a/release/src/router/busybox/coreutils/cal.c b/release/src/router/busybox/coreutils/cal.c
index ed480dd7..9b597772 100644
--- a/release/src/router/busybox/coreutils/cal.c
+++ b/release/src/router/busybox/coreutils/cal.c
@@ -1,36 +1,11 @@
-/* NOTE:
- *
- * Apparently, all "Steven J. Merrifield" did was grab the util-linux cal applet,
- * spend maybe 5 minutes integrating it into busybox, slapped a copyright on it,
- * and submitted it. I certainly saw no evidence of any attempt at size reduction.
- * Not only do I consider his copyright below meaningless, I also consider his
- * actions shameful.
- *
- * Manuel Novoa III (mjn3@codepoet.org)
- */
-
+/* vi: set sw=4 ts=4: */
/*
* Calendar implementation for busybox
*
- * Copyright (C) 2001 by Steven J. Merrifield <steve@labyrinth.net.au>
- *
* See original copyright at the end of this file
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
/* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */
/* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream
@@ -42,53 +17,39 @@
* Major size reduction... over 50% (>1.5k) on i386.
*/
-#include <sys/types.h>
-#include <ctype.h>
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "busybox.h"
+#include "libbb.h"
-#ifdef CONFIG_LOCALE_SUPPORT
-#include <locale.h>
-#endif
+/* We often use "unsigned" intead of "int", it's easier to div on most CPUs */
#define THURSDAY 4 /* for reformation */
-#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
+#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
-#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
-#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
+#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
+#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
#define MAXDAYS 42 /* max slots in a month array */
#define SPACE -1 /* used in day array */
-static const char days_in_month[] = {
+static const unsigned char days_in_month[] ALIGN1 = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
-static const char sep1752[] = {
- 1, 2, 14, 15, 16,
+static const unsigned char sep1752[] ALIGN1 = {
+ 1, 2, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30
};
-static int julian;
+/* Set to 0 or 1 in main */
+#define julian ((unsigned)option_mask32)
-/* leap year -- account for gregorian reformation in 1752 */
-#define leap_year(yr) \
- ((yr) <= 1752 ? !((yr) % 4) : \
- (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400))
-
-static int is_leap_year(int year)
+/* leap year -- account for Gregorian reformation in 1752 */
+static int leap_year(unsigned yr)
{
- return leap_year(year);
+ if (yr <= 1752)
+ return !(yr % 4);
+ return (!(yr % 4) && (yr % 100)) || !(yr % 400);
}
-#undef leap_year
-#define leap_year(yr) is_leap_year(yr)
/* number of centuries since 1700, not inclusive */
#define centuries_since_1700(yr) \
@@ -102,12 +63,12 @@ static int is_leap_year(int year)
#define leap_years_since_year_1(yr) \
((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
-static void center __P((char *, int, int));
-static void day_array __P((int, int, int *));
-static void trim_trailing_spaces_and_print __P((char *));
+static void center(char *, unsigned, unsigned);
+static void day_array(unsigned, unsigned, unsigned *);
+static void trim_trailing_spaces_and_print(char *);
static void blank_string(char *buf, size_t buflen);
-static char *build_row(char *p, int *dp);
+static char *build_row(char *p, unsigned *dp);
#define DAY_LEN 3 /* 3 spaces per day */
#define J_DAY_LEN (DAY_LEN + 1)
@@ -115,29 +76,25 @@ static char *build_row(char *p, int *dp);
#define J_WEEK_LEN (WEEK_LEN + 7)
#define HEAD_SEP 2 /* spaces between day headings */
+int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int cal_main(int argc, char **argv)
{
struct tm *local_time;
struct tm zero_tm;
time_t now;
- int month, year, flags, i;
+ unsigned month, year, flags, i;
char *month_names[12];
char day_headings[28]; /* 28 for julian, 21 for nonjulian */
char buf[40];
-#ifdef CONFIG_LOCALE_SUPPORT
- setlocale(LC_TIME, "");
-#endif
-
- flags = bb_getopt_ulflags(argc, argv, "jy");
-
- julian = flags & 1;
-
- argv += optind;
-
+ flags = getopt32(argv, "jy");
+ /* This sets julian = flags & 1: */
+ option_mask32 &= 1;
month = 0;
+ argv += optind;
+ argc -= optind;
- if ((argc -= optind) > 2) {
+ if (argc > 2) {
bb_show_usage();
}
@@ -145,23 +102,23 @@ int cal_main(int argc, char **argv)
time(&now);
local_time = localtime(&now);
year = local_time->tm_year + 1900;
- if (!(flags & 2)) {
+ if (!(flags & 2)) { /* no -y */
month = local_time->tm_mon + 1;
}
} else {
if (argc == 2) {
- month = bb_xgetularg10_bnd(*argv++, 1, 12);
+ month = xatou_range(*argv++, 1, 12);
}
- year = bb_xgetularg10_bnd(*argv, 1, 9999);
+ year = xatou_range(*argv, 1, 9999);
}
- blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian);
+ blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian);
i = 0;
do {
zero_tm.tm_mon = i;
strftime(buf, sizeof(buf), "%B", &zero_tm);
- month_names[i] = bb_xstrdup(buf);
+ month_names[i] = xstrdup(buf);
if (i < 7) {
zero_tm.tm_wday = i;
@@ -171,13 +128,13 @@ int cal_main(int argc, char **argv)
} while (++i < 12);
if (month) {
- int row, len, days[MAXDAYS];
- int *dp = days;
+ unsigned row, len, days[MAXDAYS];
+ unsigned *dp = days;
char lineout[30];
-
+
day_array(month, year, dp);
len = sprintf(lineout, "%s %d", month_names[month - 1], year);
- bb_printf("%*s%s\n%s\n",
+ printf("%*s%s\n%s\n",
((7*julian + WEEK_LEN) - len) / 2, "",
lineout, day_headings);
for (row = 0; row < 6; row++) {
@@ -186,10 +143,10 @@ int cal_main(int argc, char **argv)
trim_trailing_spaces_and_print(lineout);
}
} else {
- int row, which_cal, week_len, days[12][MAXDAYS];
- int *dp;
+ unsigned row, which_cal, week_len, days[12][MAXDAYS];
+ unsigned *dp;
char lineout[80];
-
+
sprintf(lineout, "%d", year);
center(lineout,
(WEEK_LEN * 3 + HEAD_SEP * 2)
@@ -208,11 +165,11 @@ int cal_main(int argc, char **argv)
center(month_names[month + 1], week_len, HEAD_SEP);
}
center(month_names[month + 2 - julian], week_len, 0);
- bb_printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings);
+ printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings);
if (!julian) {
- bb_printf("%*s%s", HEAD_SEP, "", day_headings);
+ printf("%*s%s", HEAD_SEP, "", day_headings);
}
- putchar('\n');
+ bb_putchar('\n');
for (row = 0; row < (6*7); row += 7) {
for (which_cal = 0; which_cal < 3-julian; which_cal++) {
dp = days[month + which_cal] + row;
@@ -224,7 +181,7 @@ int cal_main(int argc, char **argv)
}
}
- bb_fflush_stdout_and_exit(0);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
}
/*
@@ -234,27 +191,30 @@ int cal_main(int argc, char **argv)
* out end to end. You would have 42 numbers or spaces. This routine
* builds that array for any month from Jan. 1 through Dec. 9999.
*/
-static void day_array(int month, int year, int *days)
+static void day_array(unsigned month, unsigned year, unsigned *days)
{
- long temp;
- int i;
- int j_offset;
- int day, dw, dm;
+ unsigned long temp;
+ unsigned i;
+ unsigned day, dw, dm;
memset(days, SPACE, MAXDAYS * sizeof(int));
if ((month == 9) && (year == 1752)) {
- j_offset = julian * 244;
- i = 0;
+ /* Assumes the Gregorian reformation eliminates
+ * 3 Sep. 1752 through 13 Sep. 1752.
+ */
+ unsigned j_offset = julian * 244;
+ size_t oday = 0;
+
do {
- days[i+2] = sep1752[i] + j_offset;
- } while (++i < sizeof(sep1752));
+ days[oday+2] = sep1752[oday] + j_offset;
+ } while (++oday < sizeof(sep1752));
return;
}
/* day_in_year
- * return the 1 based day number within the year
+ * return the 1 based day number within the year
*/
day = 1;
if ((month > 2) && leap_year(year)) {
@@ -267,17 +227,15 @@ static void day_array(int month, int year, int *days)
}
/* day_in_week
- * return the 0 based day number for any date from 1 Jan. 1 to
- * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
- * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
- * missing days.
+ * return the 0 based day number for any date from 1 Jan. 1 to
+ * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
+ * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
+ * missing days.
*/
- dw = THURSDAY;
- temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
- + day;
+ temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day;
if (temp < FIRST_MISSING_DAY) {
dw = ((temp - 1 + SATURDAY) % 7);
- } else if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS)) {
+ } else {
dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
}
@@ -290,10 +248,9 @@ static void day_array(int month, int year, int *days)
++dm;
}
- while (dm) {
+ do {
days[dw++] = day++;
- --dm;
- }
+ } while (--dm);
}
static void trim_trailing_spaces_and_print(char *s)
@@ -303,7 +260,7 @@ static void trim_trailing_spaces_and_print(char *s)
while (*p) {
++p;
}
- while (p > s) {
+ while (p != s) {
--p;
if (!(isspace)(*p)) { /* We want the function... not the inline. */
p[1] = '\0';
@@ -314,11 +271,11 @@ static void trim_trailing_spaces_and_print(char *s)
puts(s);
}
-static void center(char *str, int len, int separate)
+static void center(char *str, unsigned len, unsigned separate)
{
- int n = strlen(str);
+ unsigned n = strlen(str);
len -= n;
- bb_printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, "");
+ printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, "");
}
static void blank_string(char *buf, size_t buflen)
@@ -327,24 +284,26 @@ static void blank_string(char *buf, size_t buflen)
buf[buflen-1] = '\0';
}
-static char *build_row(char *p, int *dp)
+static char *build_row(char *p, unsigned *dp)
{
- int col, val, day;
-
+ unsigned col, val, day;
+
memset(p, ' ', (julian + DAY_LEN) * 7);
col = 0;
do {
- if ((day = *dp++) != SPACE) {
+ day = *dp++;
+ if (day != SPACE) {
if (julian) {
- *++p;
+ ++p;
if (day >= 100) {
*p = '0';
p[-1] = (day / 100) + '0';
day %= 100;
}
}
- if ((val = day / 10) > 0) {
+ val = day / 10;
+ if (val > 0) {
*p = val + '0';
}
*++p = day % 10 + '0';
@@ -388,5 +347,3 @@ static char *build_row(char *p, int *dp)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
-
diff --git a/release/src/router/busybox/coreutils/cat.c b/release/src/router/busybox/coreutils/cat.c
index 86527576..0024eb8d 100644
--- a/release/src/router/busybox/coreutils/cat.c
+++ b/release/src/router/busybox/coreutils/cat.c
@@ -4,64 +4,45 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2, see file License in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * This is a new implementation of 'cat' which aims to be SUSv3 compliant.
- *
- * Changes from the previous implementation include:
- * 1) Multiple '-' args are accepted as required by SUSv3. The previous
- * implementation would close stdin and segfault on a subsequent '-'.
- * 2) The '-u' options is required by SUSv3. Note that the specified
- * behavior for '-u' is done by default, so all we need do is accept
- * the option.
- */
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include "busybox.h"
-extern int cat_main(int argc, char **argv)
+int bb_cat(char **argv)
{
- FILE *f;
+ int fd;
int retval = EXIT_SUCCESS;
- bb_getopt_ulflags(argc, argv, "u");
-
- argv += optind;
- if (!*argv) {
- *--argv = "-";
- }
+ if (!*argv)
+ argv = (char**) &bb_argv_dash;
do {
- if ((f = bb_wfopen_input(*argv)) != NULL) {
- int r = bb_copyfd(fileno(f), STDOUT_FILENO, 0);
- bb_fclose_nonstdin(f);
- if (r >= 0) {
+ fd = open_or_warn_stdin(*argv);
+ if (fd >= 0) {
+ /* This is not a xfunc - never exits */
+ off_t r = bb_copyfd_eof(fd, STDOUT_FILENO);
+ if (fd != STDIN_FILENO)
+ close(fd);
+ if (r >= 0)
continue;
- }
}
retval = EXIT_FAILURE;
} while (*++argv);
return retval;
}
+
+int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cat_main(int argc UNUSED_PARAM, char **argv)
+{
+ getopt32(argv, "u");
+ argv += optind;
+ return bb_cat(argv);
+}
diff --git a/release/src/router/busybox/coreutils/catv.c b/release/src/router/busybox/coreutils/catv.c
new file mode 100644
index 00000000..ff3139c8
--- /dev/null
+++ b/release/src/router/busybox/coreutils/catv.c
@@ -0,0 +1,75 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cat -v implementation for busybox
+ *
+ * Copyright (C) 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+/* See "Cat -v considered harmful" at
+ * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */
+
+#include "libbb.h"
+
+int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int catv_main(int argc UNUSED_PARAM, char **argv)
+{
+ int retval = EXIT_SUCCESS;
+ int fd;
+ unsigned flags;
+
+ flags = getopt32(argv, "etv");
+#define CATV_OPT_e (1<<0)
+#define CATV_OPT_t (1<<1)
+#define CATV_OPT_v (1<<2)
+ flags ^= CATV_OPT_v;
+ argv += optind;
+
+ /* Read from stdin if there's nothing else to do. */
+ if (!argv[0])
+ *--argv = (char*)"-";
+ do {
+ fd = open_or_warn_stdin(*argv);
+ if (fd < 0) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+ for (;;) {
+ int i, res;
+
+#define read_buf bb_common_bufsiz1
+ res = read(fd, read_buf, COMMON_BUFSIZE);
+ if (res < 0)
+ retval = EXIT_FAILURE;
+ if (res < 1)
+ break;
+ for (i = 0; i < res; i++) {
+ unsigned char c = read_buf[i];
+
+ if (c > 126 && (flags & CATV_OPT_v)) {
+ if (c == 127) {
+ printf("^?");
+ continue;
+ }
+ printf("M-");
+ c -= 128;
+ }
+ if (c < 32) {
+ if (c == 10) {
+ if (flags & CATV_OPT_e)
+ bb_putchar('$');
+ } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) {
+ printf("^%c", c+'@');
+ continue;
+ }
+ }
+ bb_putchar(c);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP && fd)
+ close(fd);
+ } while (*++argv);
+
+ fflush_stdout_and_exit(retval);
+}
diff --git a/release/src/router/busybox/coreutils/chgrp.c b/release/src/router/busybox/coreutils/chgrp.c
index 2f3fa419..7f390480 100644
--- a/release/src/router/busybox/coreutils/chgrp.c
+++ b/release/src/router/busybox/coreutils/chgrp.c
@@ -2,84 +2,30 @@
/*
* Mini chgrp implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* BB_AUDIT SUSv3 defects - unsupported options -h, -H, -L, and -P. */
-/* BB_AUDIT GNU defects - unsupported options -h, -c, -f, -v, and long options. */
-/* BB_AUDIT Note: gnu chgrp does not support -H, -L, or -P. */
+/* BB_AUDIT SUSv3 defects - none? */
+/* BB_AUDIT GNU defects - unsupported long options. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-/* Don't use lchown glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
+/* This is a NOEXEC applet. Be very careful! */
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
- if (lchown(fileName, statbuf->st_uid, *((long *) junk)) == 0) {
- return (TRUE);
- }
- bb_perror_msg("%s", fileName); /* Avoid multibyte problems. */
- return (FALSE);
-}
+int chgrp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int chgrp_main(int argc, char **argv)
{
- long gid;
- int recursiveFlag;
- int retval = EXIT_SUCCESS;
- char *p;
-
- recursiveFlag = bb_getopt_ulflags(argc, argv, "R");
-
- if (argc - optind < 2) {
- bb_show_usage();
- }
-
- argv += optind;
-
- /* Find the selected group */
- gid = strtoul(*argv, &p, 10); /* maybe it's already numeric */
- if (*p || (p == *argv)) { /* trailing chars or nonnumeric */
- gid = my_getgrnam(*argv);
- }
- ++argv;
-
- /* Ok, ready to do the deed now */
- do {
- if (! recursive_action (*argv, recursiveFlag, FALSE, FALSE,
- fileAction, fileAction, &gid)) {
- retval = EXIT_FAILURE;
+ /* "chgrp [opts] abc file(s)" == "chown [opts] :abc file(s)" */
+ char **p = argv;
+ while (*++p) {
+ if (p[0][0] != '-') {
+ p[0] = xasprintf(":%s", p[0]);
+ break;
}
- } while (*++argv);
-
- return retval;
+ }
+ return chown_main(argc, argv);
}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/coreutils/chmod.c b/release/src/router/busybox/coreutils/chmod.c
index 390cc6d2..40f681fb 100644
--- a/release/src/router/busybox/coreutils/chmod.c
+++ b/release/src/router/busybox/coreutils/chmod.c
@@ -2,100 +2,113 @@
/*
* Mini chmod implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* Reworked by (C) 2002 Vladimir Oleynik <dzo@simtreas.ru>
* to correctly parse '-rwxgoa'
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
-/* BB_AUDIT GNU defects - unsupported options -c, -f, -v, and long options. */
+/* BB_AUDIT GNU defects - unsupported long options. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define OPT_RECURSE (option_mask32 & 1)
+#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 2) SKIP_DESKTOP(0))
+#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))
+#define OPT_QUIET (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))
+#define OPT_STR "R" USE_DESKTOP("vcf")
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
+/* coreutils:
+ * chmod never changes the permissions of symbolic links; the chmod
+ * system call cannot change their permissions. This is not a problem
+ * since the permissions of symbolic links are never used.
+ * However, for each symbolic link listed on the command line, chmod changes
+ * the permissions of the pointed-to file. In contrast, chmod ignores
+ * symbolic links encountered during recursive directory traversals.
+ */
+
+static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void* param, int depth)
{
- if (!bb_parse_mode((char *)junk, &(statbuf->st_mode)))
- bb_error_msg_and_die( "invalid mode: %s", (char *)junk);
- if (chmod(fileName, statbuf->st_mode) == 0)
- return (TRUE);
- bb_perror_msg("%s", fileName); /* Avoid multibyte problems. */
- return (FALSE);
+ mode_t newmode;
+
+ /* match coreutils behavior */
+ if (depth == 0) {
+ /* statbuf holds lstat result, but we need stat (follow link) */
+ if (stat(fileName, statbuf))
+ goto err;
+ } else { /* depth > 0: skip links */
+ if (S_ISLNK(statbuf->st_mode))
+ return TRUE;
+ }
+ newmode = statbuf->st_mode;
+
+ if (!bb_parse_mode((char *)param, &newmode))
+ bb_error_msg_and_die("invalid mode: %s", (char *)param);
+
+ if (chmod(fileName, newmode) == 0) {
+ if (OPT_VERBOSE
+ || (OPT_CHANGED && statbuf->st_mode != newmode)
+ ) {
+ printf("mode of '%s' changed to %04o (%s)\n", fileName,
+ newmode & 07777, bb_mode_string(newmode)+1);
+ }
+ return TRUE;
+ }
+ err:
+ if (!OPT_QUIET)
+ bb_simple_perror_msg(fileName);
+ return FALSE;
}
-int chmod_main(int argc, char **argv)
+int chmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int chmod_main(int argc UNUSED_PARAM, char **argv)
{
int retval = EXIT_SUCCESS;
- int recursiveFlag = FALSE;
- int count;
+ char *arg, **argp;
char *smode;
- char **p;
- char *p0;
- char opt = '-';
-
- ++argv;
- count = 0;
-
- for (p = argv ; *p ; p++) {
- p0 = p[0];
- if (p0[0] == opt) {
- if ((p0[1] == '-') && !p0[2]) {
- opt = 0; /* Disable further option processing. */
- continue;
- }
- if (p0[1] == 'R') {
- char *s = p0 + 2;
- while (*s == 'R') {
- ++s;
- }
- if (*s) {
- bb_show_usage();
- }
- recursiveFlag = TRUE;
- continue;
- }
- if (count) {
- bb_show_usage();
- }
+
+ /* Convert first encountered -r into ar, -w into aw etc
+ * so that getopt would not eat it */
+ argp = argv;
+ while ((arg = *++argp)) {
+ /* Mode spec must be the first arg (sans -R etc) */
+ /* (protect against mishandling e.g. "chmod 644 -r") */
+ if (arg[0] != '-') {
+ arg = NULL;
+ break;
+ }
+ /* An option. Not a -- or valid option? */
+ if (arg[1] && !strchr("-"OPT_STR, arg[1])) {
+ arg[0] = 'a';
+ break;
}
- argv[count] = p0;
- ++count;
}
- argv[count] = NULL;
+ /* Parse options */
+ opt_complementary = "-2";
+ getopt32(argv, ("-"OPT_STR) + 1); /* Reuse string */
+ argv += optind;
- if (count < 2) {
- bb_show_usage();
- }
-
- smode = *argv;
- ++argv;
+ /* Restore option-like mode if needed */
+ if (arg) arg[0] = '-';
/* Ok, ready to do the deed now */
+ smode = *argv++;
do {
- if (! recursive_action (*argv, recursiveFlag, FALSE, FALSE,
- fileAction, fileAction, smode)) {
+ if (!recursive_action(*argv,
+ OPT_RECURSE, // recurse
+ fileAction, // file action
+ fileAction, // dir action
+ smode, // user data
+ 0) // depth
+ ) {
retval = EXIT_FAILURE;
}
} while (*++argv);
@@ -104,9 +117,44 @@ int chmod_main(int argc, char **argv)
}
/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
+Security: chmod is too important and too subtle.
+This is a test script (busybox chmod versus coreutils).
+Run it in empty directory.
+
+#!/bin/sh
+t1="/tmp/busybox chmod"
+t2="/usr/bin/chmod"
+create() {
+ rm -rf $1; mkdir $1
+ (
+ cd $1 || exit 1
+ mkdir dir
+ >up
+ >file
+ >dir/file
+ ln -s dir linkdir
+ ln -s file linkfile
+ ln -s ../up dir/up
+ )
+}
+tst() {
+ (cd test1; $t1 $1)
+ (cd test2; $t2 $1)
+ (cd test1; ls -lR) >out1
+ (cd test2; ls -lR) >out2
+ echo "chmod $1" >out.diff
+ if ! diff -u out1 out2 >>out.diff; then exit 1; fi
+ rm out.diff
+}
+echo "If script produced 'out.diff' file, then at least one testcase failed"
+create test1; create test2
+tst "a+w file"
+tst "a-w dir"
+tst "a+w linkfile"
+tst "a-w linkdir"
+tst "-R a+w file"
+tst "-R a-w dir"
+tst "-R a+w linkfile"
+tst "-R a-w linkdir"
+tst "a-r,a+x linkfile"
*/
diff --git a/release/src/router/busybox/coreutils/chown.c b/release/src/router/busybox/coreutils/chown.c
index 7b9ea917..34524926 100644
--- a/release/src/router/busybox/coreutils/chown.c
+++ b/release/src/router/busybox/coreutils/chown.c
@@ -2,105 +2,114 @@
/*
* Mini chown implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* BB_AUDIT SUSv3 defects - unsupported options -h, -H, -L, and -P. */
-/* BB_AUDIT GNU defects - unsupported options -h, -c, -f, -v, and long options. */
-/* BB_AUDIT Note: gnu chown does not support -H, -L, or -P. */
+/* BB_AUDIT SUSv3 defects - none? */
+/* BB_AUDIT GNU defects - unsupported long options. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "busybox.h"
-
-/* Don't use lchown for glibc older then 2.1.x */
-#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
-#define lchown chown
-#endif
-
-static long uid;
-static long gid;
-
-static int (*chown_func)(const char *, uid_t, gid_t) = chown;
-
-static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
-{
- if (chown_func(fileName, uid, (gid == -1) ? statbuf->st_gid : gid) == 0) {
- return (TRUE);
- }
- bb_perror_msg("%s", fileName); /* Avoid multibyte problems. */
- return (FALSE);
-}
-
-#define FLAG_R 1
-#define FLAG_h 2
-
-static unsigned long get_ug_id(const char *s, long (*my_getxxnam)(const char *))
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+
+#define OPT_STR ("Rh" USE_DESKTOP("vcfLHP"))
+#define BIT_RECURSE 1
+#define OPT_RECURSE (opt & 1)
+#define OPT_NODEREF (opt & 2)
+#define OPT_VERBOSE (USE_DESKTOP(opt & 0x04) SKIP_DESKTOP(0))
+#define OPT_CHANGED (USE_DESKTOP(opt & 0x08) SKIP_DESKTOP(0))
+#define OPT_QUIET (USE_DESKTOP(opt & 0x10) SKIP_DESKTOP(0))
+/* POSIX options
+ * -L traverse every symbolic link to a directory encountered
+ * -H if a command line argument is a symbolic link to a directory, traverse it
+ * -P do not traverse any symbolic links (default)
+ * We do not conform to the following:
+ * "Specifying more than one of -H, -L, and -P is not an error.
+ * The last option specified shall determine the behavior of the utility." */
+/* -L */
+#define BIT_TRAVERSE 0x20
+#define OPT_TRAVERSE (USE_DESKTOP(opt & BIT_TRAVERSE) SKIP_DESKTOP(0))
+/* -H or -L */
+#define BIT_TRAVERSE_TOP (0x20|0x40)
+#define OPT_TRAVERSE_TOP (USE_DESKTOP(opt & BIT_TRAVERSE_TOP) SKIP_DESKTOP(0))
+
+typedef int (*chown_fptr)(const char *, uid_t, gid_t);
+
+struct param_t {
+ struct bb_uidgid_t ugid;
+ chown_fptr chown_func;
+};
+
+static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf,
+ void *vparam, int depth UNUSED_PARAM)
{
- unsigned long r;
- char *p;
-
- r = strtoul(s, &p, 10);
- if (*p || (s == p)) {
- r = my_getxxnam(s);
+#define param (*(struct param_t*)vparam)
+#define opt option_mask32
+ uid_t u = (param.ugid.uid == (uid_t)-1) ? statbuf->st_uid : param.ugid.uid;
+ gid_t g = (param.ugid.gid == (gid_t)-1) ? statbuf->st_gid : param.ugid.gid;
+
+ if (param.chown_func(fileName, u, g) == 0) {
+ if (OPT_VERBOSE
+ || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
+ ) {
+ printf("changed ownership of '%s' to %u:%u\n",
+ fileName, (unsigned)u, (unsigned)g);
+ }
+ return TRUE;
}
-
- return r;
+ if (!OPT_QUIET)
+ bb_simple_perror_msg(fileName); /* A filename can have % in it... */
+ return FALSE;
+#undef opt
+#undef param
}
-int chown_main(int argc, char **argv)
+int chown_main(int argc UNUSED_PARAM, char **argv)
{
- int flags;
int retval = EXIT_SUCCESS;
- char *groupName;
+ int opt, flags;
+ struct param_t param;
- flags = bb_getopt_ulflags(argc, argv, "Rh");
-
- if (flags & FLAG_h) chown_func = lchown;
-
- if (argc - optind < 2) {
- bb_show_usage();
- }
+ param.ugid.uid = -1;
+ param.ugid.gid = -1;
+ param.chown_func = chown;
+ opt_complementary = "-2";
+ opt = getopt32(argv, OPT_STR);
argv += optind;
- /* First, check if there is a group name here */
- if ((groupName = strchr(*argv, '.')) == NULL) {
- groupName = strchr(*argv, ':');
+ /* This matches coreutils behavior (almost - see below) */
+ if (OPT_NODEREF
+ /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
+ USE_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
+ ) {
+ param.chown_func = lchown;
}
- gid = -1;
- if (groupName) {
- *groupName++ = '\0';
- gid = get_ug_id(groupName, my_getgrnam);
- }
+ flags = ACTION_DEPTHFIRST; /* match coreutils order */
+ if (OPT_RECURSE)
+ flags |= ACTION_RECURSE;
+ if (OPT_TRAVERSE_TOP)
+ flags |= ACTION_FOLLOWLINKS_L0; /* -H/-L: follow links on depth 0 */
+ if (OPT_TRAVERSE)
+ flags |= ACTION_FOLLOWLINKS; /* follow links if -L */
- /* Now check for the username */
- uid = get_ug_id(*argv, my_getpwnam);
+ parse_chown_usergroup_or_die(&param.ugid, argv[0]);
- ++argv;
-
/* Ok, ready to do the deed now */
+ argv++;
do {
- if (! recursive_action (*argv, (flags & FLAG_R), FALSE, FALSE,
- fileAction, fileAction, NULL)) {
+ if (!recursive_action(*argv,
+ flags, /* flags */
+ fileAction, /* file action */
+ fileAction, /* dir action */
+ &param, /* user data */
+ 0) /* depth */
+ ) {
retval = EXIT_FAILURE;
}
} while (*++argv);
@@ -109,9 +118,63 @@ int chown_main(int argc, char **argv)
}
/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
+Testcase. Run in empty directory.
+
+#!/bin/sh
+t1="/tmp/busybox chown"
+t2="/usr/bin/chown"
+create() {
+ rm -rf $1; mkdir $1
+ (
+ cd $1 || exit 1
+ mkdir dir dir2
+ >up
+ >file
+ >dir/file
+ >dir2/file
+ ln -s dir linkdir
+ ln -s file linkfile
+ ln -s ../up dir/linkup
+ ln -s ../dir2 dir/linkupdir2
+ )
+ chown -R 0:0 $1
+}
+tst() {
+ create test1
+ create test2
+ echo "[$1]" >>test1.out
+ echo "[$1]" >>test2.out
+ (cd test1; $t1 $1) >>test1.out 2>&1
+ (cd test2; $t2 $1) >>test2.out 2>&1
+ (cd test1; ls -lnR) >out1
+ (cd test2; ls -lnR) >out2
+ echo "chown $1" >out.diff
+ if ! diff -u out1 out2 >>out.diff; then exit 1; fi
+ rm out.diff
+}
+tst_for_each() {
+ tst "$1 1:1 file"
+ tst "$1 1:1 dir"
+ tst "$1 1:1 linkdir"
+ tst "$1 1:1 linkfile"
+}
+echo "If script produced 'out.diff' file, then at least one testcase failed"
+>test1.out
+>test2.out
+# These match coreutils 6.8:
+tst_for_each "-v"
+tst_for_each "-vR"
+tst_for_each "-vRP"
+tst_for_each "-vRL"
+tst_for_each "-vRH"
+tst_for_each "-vh"
+tst_for_each "-vhR"
+tst_for_each "-vhRP"
+tst_for_each "-vhRL"
+tst_for_each "-vhRH"
+# Fix `name' in coreutils output
+sed 's/`/'"'"'/g' -i test2.out
+# Compare us with coreutils output
+diff -u test1.out test2.out
+
*/
diff --git a/release/src/router/busybox/coreutils/chroot.c b/release/src/router/busybox/coreutils/chroot.c
index 5562e58c..1198a415 100644
--- a/release/src/router/busybox/coreutils/chroot.c
+++ b/release/src/router/busybox/coreutils/chroot.c
@@ -2,32 +2,16 @@
/*
* Mini chroot implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include "busybox.h"
+#include "libbb.h"
+int chroot_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int chroot_main(int argc, char **argv)
{
if (argc < 2) {
@@ -35,19 +19,19 @@ int chroot_main(int argc, char **argv)
}
++argv;
- if (chroot(*argv) || (chdir("/"))) {
- bb_perror_msg_and_die("cannot change root directory to %s", *argv);
- }
+ xchroot(*argv);
+ xchdir("/");
++argv;
if (argc == 2) {
argv -= 2;
- if (!(*argv = getenv("SHELL"))) {
- *argv = (char *) "/bin/sh";
+ argv[0] = getenv("SHELL");
+ if (!argv[0]) {
+ argv[0] = (char *) DEFAULT_SHELL;
}
argv[1] = (char *) "-i";
}
- execvp(*argv, argv);
+ BB_EXECVP(*argv, argv);
bb_perror_msg_and_die("cannot execute %s", *argv);
}
diff --git a/release/src/router/busybox/coreutils/cksum.c b/release/src/router/busybox/coreutils/cksum.c
new file mode 100644
index 00000000..3a77c753
--- /dev/null
+++ b/release/src/router/busybox/coreutils/cksum.c
@@ -0,0 +1,67 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * cksum - calculate the CRC32 checksum of a file
+ *
+ * Copyright (C) 2006 by Rob Sullivan, with ideas from code by Walter Harms
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */
+
+#include "libbb.h"
+
+int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cksum_main(int argc UNUSED_PARAM, char **argv)
+{
+ uint32_t *crc32_table = crc32_filltable(NULL, 1);
+ uint32_t crc;
+ off_t length, filesize;
+ int bytes_read;
+ int exit_code = EXIT_SUCCESS;
+ uint8_t *cp;
+
+#if ENABLE_DESKTOP
+ getopt32(argv, ""); /* coreutils 6.9 compat */
+ argv += optind;
+#else
+ argv++;
+#endif
+
+ do {
+ int fd = open_or_warn_stdin(*argv ? *argv : bb_msg_standard_input);
+
+ if (fd < 0) {
+ exit_code = EXIT_FAILURE;
+ continue;
+ }
+ crc = 0;
+ length = 0;
+
+#define read_buf bb_common_bufsiz1
+ while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) {
+ cp = (uint8_t *) read_buf;
+ length += bytes_read;
+ do {
+ crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++];
+ } while (--bytes_read);
+ }
+ close(fd);
+
+ filesize = length;
+
+ while (length) {
+ crc = (crc << 8) ^ crc32_table[(uint8_t)(crc >> 24) ^ (uint8_t)length];
+ /* must ensure that shift is unsigned! */
+ if (sizeof(length) <= sizeof(unsigned))
+ length = (unsigned)length >> 8;
+ else if (sizeof(length) <= sizeof(unsigned long))
+ length = (unsigned long)length >> 8;
+ else
+ length = (unsigned long long)length >> 8;
+ }
+ crc = ~crc;
+
+ printf((*argv ? "%"PRIu32" %"OFF_FMT"i %s\n" : "%"PRIu32" %"OFF_FMT"i\n"),
+ crc, filesize, *argv);
+ } while (*argv && *++argv);
+
+ fflush_stdout_and_exit(exit_code);
+}
diff --git a/release/src/router/busybox/coreutils/cmp.c b/release/src/router/busybox/coreutils/cmp.c
deleted file mode 100644
index 43dbc842..00000000
--- a/release/src/router/busybox/coreutils/cmp.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini cmp implementation for busybox
- *
- * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
-/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
-
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * Original version majorly reworked for SUSv3 compliance, bug fixes, and
- * size optimizations. Changes include:
- * 1) Now correctly distingusishes between errors and actual file differences.
- * 2) Proper handling of '-' args.
- * 3) Actual error checking of i/o.
- * 4) Accept SUSv3 -l option. Note that we use the slightly nicer gnu format
- * in the '-l' case.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
-
-static FILE *cmp_xfopen_input(const char *filename)
-{
- FILE *fp;
-
- if ((fp = bb_wfopen_input(filename)) != NULL) {
- return fp;
- }
-
- exit(bb_default_error_retval); /* We already output an error message. */
-}
-
-static const char fmt_eof[] = "cmp: EOF on %s\n";
-static const char fmt_differ[] = "%s %s differ: char %d, line %d\n";
-#if 0
-static const char fmt_l_opt[] = "%.0s%.0s%d %o %o\n"; /* SUSv3 format */
-#else
-static const char fmt_l_opt[] = "%.0s%.0s%d %3o %3o\n"; /* nicer gnu format */
-#endif
-
-static const char opt_chars[] = "sl";
-
-enum {
- OPT_s = 1,
- OPT_l = 2
-};
-
-int cmp_main(int argc, char **argv)
-{
- FILE *fp1, *fp2, *outfile = stdout;
- const char *filename1, *filename2;
- const char *fmt;
- int c1, c2, char_pos, line_pos;
- int opt_flags;
- int exit_val = 0;
-
- bb_default_error_retval = 2; /* 1 is returned if files are different. */
-
- opt_flags = bb_getopt_ulflags(argc, argv, opt_chars);
-
- if ((opt_flags == 3) || (((unsigned int)(--argc - optind)) > 1)) {
- bb_show_usage();
- }
-
- fp1 = cmp_xfopen_input(filename1 = *(argv += optind));
-
- filename2 = "-";
- if (*++argv) {
- filename2 = *argv;
- }
- fp2 = cmp_xfopen_input(filename2);
-
- if (fp1 == fp2) { /* Paranioa check... stdin == stdin? */
- /* Note that we don't bother reading stdin. Neither does gnu wc.
- * But perhaps we should, so that other apps down the chain don't
- * get the input. Consider 'echo hello | (cmp - - && cat -)'.
- */
- return 0;
- }
-
- fmt = fmt_differ;
- if (opt_flags == OPT_l) {
- fmt = fmt_l_opt;
- }
-
- char_pos = 0;
- line_pos = 1;
- do {
- c1 = getc(fp1);
- c2 = getc(fp2);
- ++char_pos;
- if (c1 != c2) { /* Remember -- a read error may have occurred. */
- exit_val = 1; /* But assume the files are different for now. */
- if (c2 == EOF) {
- /* We know that fp1 isn't at EOF or in an error state. But to
- * save space below, things are setup to expect an EOF in fp1
- * if an EOF occurred. So, swap things around.
- */
- fp1 = fp2;
- filename1 = filename2;
- c1 = c2;
- }
- if (c1 == EOF) {
- bb_xferror(fp1, filename1);
- fmt = fmt_eof; /* Well, no error, so it must really be EOF. */
- outfile = stderr;
- /* There may have been output to stdout (option -l), so
- * make sure we fflush before writing to stderr. */
- bb_xfflush_stdout();
- }
- if (opt_flags != OPT_s) {
- if (opt_flags == OPT_l) {
- line_pos = c1; /* line_pos is unused in the -l case. */
- }
- bb_fprintf(outfile, fmt, filename1, filename2, char_pos, line_pos, c2);
- if (opt_flags) { /* This must be -l since not -s. */
- /* If we encountered and EOF, the while check will catch it. */
- continue;
- }
- }
- break;
- }
- if (c1 == '\n') {
- ++line_pos;
- }
- } while (c1 != EOF);
-
- bb_xferror(fp1, filename1);
- bb_xferror(fp2, filename2);
-
- bb_fflush_stdout_and_exit(exit_val);
-}
diff --git a/release/src/router/busybox/coreutils/comm.c b/release/src/router/busybox/coreutils/comm.c
new file mode 100644
index 00000000..221cbfbc
--- /dev/null
+++ b/release/src/router/busybox/coreutils/comm.c
@@ -0,0 +1,100 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini comm implementation for busybox
+ *
+ * Copyright (C) 2005 by Robert Sullivan <cogito.ergo.cogito@gmail.com>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+#define COMM_OPT_1 (1 << 0)
+#define COMM_OPT_2 (1 << 1)
+#define COMM_OPT_3 (1 << 2)
+
+/* writeline outputs the input given, appropriately aligned according to class */
+static void writeline(char *line, int class)
+{
+ int flags = option_mask32;
+ if (class == 0) {
+ if (flags & COMM_OPT_1)
+ return;
+ } else if (class == 1) {
+ if (flags & COMM_OPT_2)
+ return;
+ if (!(flags & COMM_OPT_1))
+ putchar('\t');
+ } else /*if (class == 2)*/ {
+ if (flags & COMM_OPT_3)
+ return;
+ if (!(flags & COMM_OPT_1))
+ putchar('\t');
+ if (!(flags & COMM_OPT_2))
+ putchar('\t');
+ }
+ puts(line);
+}
+
+int comm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int comm_main(int argc UNUSED_PARAM, char **argv)
+{
+ char *thisline[2];
+ FILE *stream[2];
+ int i;
+ int order;
+
+ opt_complementary = "=2";
+ getopt32(argv, "123");
+ argv += optind;
+
+ for (i = 0; i < 2; ++i) {
+ stream[i] = xfopen_stdin(argv[i]);
+ }
+
+ order = 0;
+ thisline[1] = thisline[0] = NULL;
+ while (1) {
+ if (order <= 0) {
+ free(thisline[0]);
+ thisline[0] = xmalloc_fgetline(stream[0]);
+ }
+ if (order >= 0) {
+ free(thisline[1]);
+ thisline[1] = xmalloc_fgetline(stream[1]);
+ }
+
+ i = !thisline[0] + (!thisline[1] << 1);
+ if (i)
+ break;
+ order = strcmp(thisline[0], thisline[1]);
+
+ if (order >= 0)
+ writeline(thisline[1], order ? 1 : 2);
+ else
+ writeline(thisline[0], 0);
+ }
+
+ /* EOF at least on one of the streams */
+ i &= 1;
+ if (thisline[i]) {
+ /* stream[i] is not at EOF yet */
+ /* we did not print thisline[i] yet */
+ char *p = thisline[i];
+ writeline(p, i);
+ while (1) {
+ free(p);
+ p = xmalloc_fgetline(stream[i]);
+ if (!p)
+ break;
+ writeline(p, i);
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ fclose(stream[0]);
+ fclose(stream[1]);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/coreutils/cp.c b/release/src/router/busybox/coreutils/cp.c
index c5dd31ec..71a29396 100644
--- a/release/src/router/busybox/coreutils/cp.c
+++ b/release/src/router/busybox/coreutils/cp.c
@@ -3,25 +3,11 @@
* Mini cp implementation for busybox
*
* Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
*/
-/* BB_AUDIT SUSv3 defects - unsupported options -H, -L, and -P. */
-/* BB_AUDIT GNU defects - only extension options supported are -a and -d. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
@@ -29,21 +15,14 @@
* Size reduction.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <assert.h>
-#include "busybox.h"
+#include "libbb.h"
#include "libcoreutils/coreutils.h"
-static const char cp_opts[] = "pdRfia"; /* WARNING!! ORDER IS IMPORTANT!! */
+/* This is a NOEXEC applet. Be very careful! */
+
-extern int cp_main(int argc, char **argv)
+int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cp_main(int argc, char **argv)
{
struct stat source_stat;
struct stat dest_stat;
@@ -53,60 +32,124 @@ extern int cp_main(int argc, char **argv)
int d_flags;
int flags;
int status = 0;
+ enum {
+ OPT_a = 1 << (sizeof(FILEUTILS_CP_OPTSTR)-1),
+ OPT_r = 1 << (sizeof(FILEUTILS_CP_OPTSTR)),
+ OPT_P = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+1),
+ OPT_H = 1 << (sizeof(FILEUTILS_CP_OPTSTR)+2),
+ };
- /* Since these are enums, #if tests will not work. So use assert()s. */
- assert(FILEUTILS_PRESERVE_STATUS == 1);
- assert(FILEUTILS_DEREFERENCE == 2);
- assert(FILEUTILS_RECUR == 4);
- assert(FILEUTILS_FORCE == 8);
- assert(FILEUTILS_INTERACTIVE == 16);
-
- flags = bb_getopt_ulflags(argc, argv, cp_opts);
-
- if (flags & 32) {
- flags |= (FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR | FILEUTILS_DEREFERENCE);
- }
-
- flags ^= FILEUTILS_DEREFERENCE; /* The sense of this flag was reversed. */
+ // Need at least two arguments
+ // Soft- and hardlinking doesn't mix
+ // -P and -d are the same (-P is POSIX, -d is GNU)
+ // -r and -R are the same
+ // -R (and therefore -r) turns on -d (coreutils does this)
+ // -a = -pdR
+ opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR:HL";
+ // -v (--verbose) is ignored
+ flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPHv");
+ /* Options of cp from GNU coreutils 6.10:
+ * -a, --archive
+ * -f, --force
+ * -i, --interactive
+ * -l, --link
+ * -L, --dereference
+ * -P, --no-dereference
+ * -R, -r, --recursive
+ * -s, --symbolic-link
+ * -v, --verbose
+ * -H follow command-line symbolic links in SOURCE
+ * -d same as --no-dereference --preserve=links
+ * -p same as --preserve=mode,ownership,timestamps
+ * -c same as --preserve=context
+ * NOT SUPPORTED IN BBOX:
+ * long options are not supported (even those above).
+ * --backup[=CONTROL]
+ * make a backup of each existing destination file
+ * -b like --backup but does not accept an argument
+ * --copy-contents
+ * copy contents of special files when recursive
+ * --preserve[=ATTR_LIST]
+ * preserve attributes (default: mode,ownership,timestamps),
+ * if possible additional attributes: security context,links,all
+ * --no-preserve=ATTR_LIST
+ * --parents
+ * use full source file name under DIRECTORY
+ * --remove-destination
+ * remove each existing destination file before attempting to open
+ * --sparse=WHEN
+ * control creation of sparse files
+ * --strip-trailing-slashes
+ * remove any trailing slashes from each SOURCE argument
+ * -S, --suffix=SUFFIX
+ * override the usual backup suffix
+ * -t, --target-directory=DIRECTORY
+ * copy all SOURCE arguments into DIRECTORY
+ * -T, --no-target-directory
+ * treat DEST as a normal file
+ * -u, --update
+ * copy only when the SOURCE file is newer than the destination
+ * file or when the destination file is missing
+ * -x, --one-file-system
+ * stay on this file system
+ * -Z, --context=CONTEXT
+ * (SELinux) set SELinux security context of copy to CONTEXT
+ */
+ argc -= optind;
+ argv += optind;
+ flags ^= FILEUTILS_DEREFERENCE; /* the sense of this flag was reversed */
+ /* coreutils 6.9 compat:
+ * by default, "cp" derefs symlinks (creates regular dest files),
+ * but "cp -R" does not. We switch off deref if -r or -R (see above).
+ * However, "cp -RL" must still deref symlinks: */
+ if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */
+ flags |= FILEUTILS_DEREFERENCE;
+ /* The behavior of -H is *almost* like -L, but not quite, so let's
+ * just ignore it too for fun. TODO.
+ if (flags & OPT_H) ... // deref command-line params only
+ */
- if (optind + 2 > argc) {
- bb_show_usage();
+#if ENABLE_SELINUX
+ if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) {
+ selinux_or_die();
}
+#endif
last = argv[argc - 1];
- argv += optind;
-
/* If there are only two arguments and... */
- if (optind + 2 == argc) {
+ if (argc == 2) {
s_flags = cp_mv_stat2(*argv, &source_stat,
- (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
- if ((s_flags < 0) || ((d_flags = cp_mv_stat(last, &dest_stat)) < 0)) {
- exit(EXIT_FAILURE);
- }
+ (flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
+ if (s_flags < 0)
+ return EXIT_FAILURE;
+ d_flags = cp_mv_stat(last, &dest_stat);
+ if (d_flags < 0)
+ return EXIT_FAILURE;
+
/* ...if neither is a directory or... */
if ( !((s_flags | d_flags) & 2) ||
/* ...recursing, the 1st is a directory, and the 2nd doesn't exist... */
- /* ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) */
- /* Simplify the above since FILEUTILS_RECUR >> 1 == 2. */
- ((((flags & FILEUTILS_RECUR) >> 1) & s_flags) && !d_flags)
+ ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags)
) {
/* ...do a simple copy. */
- dest = last;
- goto DO_COPY; /* Note: optind+2==argc implies argv[1]==last below. */
+ dest = last;
+ goto DO_COPY; /* NB: argc==2 -> *++argv==last */
}
}
- do {
- dest = concat_path_file(last, bb_get_last_path_component(*argv));
- DO_COPY:
+ while (1) {
+ dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
+ DO_COPY:
if (copy_file(*argv, dest, flags) < 0) {
status = 1;
}
if (*++argv == last) {
+ /* possibly leaking dest... */
break;
}
- free((void *) dest);
- } while (1);
+ free((void*)dest);
+ }
- exit(status);
+ /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */
+ return status;
}
diff --git a/release/src/router/busybox/coreutils/cut.c b/release/src/router/busybox/coreutils/cut.c
index 34ec3690..9cc22be1 100644
--- a/release/src/router/busybox/coreutils/cut.c
+++ b/release/src/router/busybox/coreutils/cut.c
@@ -1,344 +1,287 @@
-/* vi: set sw=8 ts=8: */
+/* vi: set sw=4 ts=4: */
/*
* cut.c - minimalist version of cut
*
* Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Written by Mark Whitley <markw@codepoet.org>
+ * debloated by Bernhard Reutner-Fischer
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <string.h>
-#include <limits.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
/* option vars */
-static const char optstring[] = "b:c:f:d:sn";
-#define OPT_BYTE_FLGS 1
-#define OPT_CHAR_FLGS 2
-#define OPT_FIELDS_FLGS 4
-#define OPT_DELIM_FLGS 8
-#define OPT_SUPRESS_FLGS 16
-static char part; /* (b)yte, (c)har, (f)ields */
-static unsigned int supress_non_delimited_lines;
-static char delim = '\t'; /* delimiter, default is tab */
+static const char optstring[] ALIGN1 = "b:c:f:d:sn";
+#define CUT_OPT_BYTE_FLGS (1 << 0)
+#define CUT_OPT_CHAR_FLGS (1 << 1)
+#define CUT_OPT_FIELDS_FLGS (1 << 2)
+#define CUT_OPT_DELIM_FLGS (1 << 3)
+#define CUT_OPT_SUPPRESS_FLGS (1 << 4)
struct cut_list {
int startpos;
int endpos;
};
-static const int BOL = 0;
-static const int EOL = INT_MAX;
-static const int NON_RANGE = -1;
-
-static struct cut_list *cut_lists = NULL; /* growable array holding a series of lists */
-static unsigned int nlists = 0; /* number of elements in above list */
-
+enum {
+ BOL = 0,
+ EOL = INT_MAX,
+ NON_RANGE = -1
+};
static int cmpfunc(const void *a, const void *b)
{
- struct cut_list *la = (struct cut_list *)a;
- struct cut_list *lb = (struct cut_list *)b;
-
- if (la->startpos > lb->startpos)
- return 1;
- if (la->startpos < lb->startpos)
- return -1;
- return 0;
-}
+ return (((struct cut_list *) a)->startpos -
+ ((struct cut_list *) b)->startpos);
+}
-/*
- * parse_lists() - parses a list and puts values into startpos and endpos.
- * valid list formats: N, N-, N-M, -M
- * more than one list can be seperated by commas
- */
-static void parse_lists(char *lists)
+static void cut_file(FILE *file, char delim, const struct cut_list *cut_lists, unsigned nlists)
{
- char *ltok = NULL;
- char *ntok = NULL;
- char *junk;
- int s = 0, e = 0;
-
- /* take apart the lists, one by one (they are seperated with commas */
- while ((ltok = strsep(&lists, ",")) != NULL) {
-
- /* it's actually legal to pass an empty list */
- if (strlen(ltok) == 0)
- continue;
-
- /* get the start pos */
- ntok = strsep(&ltok, "-");
- if (ntok == NULL) {
- fprintf(stderr, "Help ntok is null for starting position! What do I do?\n");
- } else if (strlen(ntok) == 0) {
- s = BOL;
- } else {
- s = strtoul(ntok, &junk, 10);
- if(*junk != '\0' || s < 0)
- bb_error_msg_and_die("invalid byte or field list");
-
- /* account for the fact that arrays are zero based, while the user
- * expects the first char on the line to be char # 1 */
- if (s != 0)
- s--;
- }
-
- /* get the end pos */
- ntok = strsep(&ltok, "-");
- if (ntok == NULL) {
- e = NON_RANGE;
- } else if (strlen(ntok) == 0) {
- e = EOL;
- } else {
- e = strtoul(ntok, &junk, 10);
- if(*junk != '\0' || e < 0)
- bb_error_msg_and_die("invalid byte or field list");
- /* if the user specified and end position of 0, that means "til the
- * end of the line */
- if (e == 0)
- e = INT_MAX;
- e--; /* again, arrays are zero based, lines are 1 based */
- if (e == s)
- e = NON_RANGE;
- }
-
- /* if there's something left to tokenize, the user past an invalid list */
- if (ltok)
- bb_error_msg_and_die("invalid byte or field list");
-
- /* add the new list */
- cut_lists = xrealloc(cut_lists, sizeof(struct cut_list) * (++nlists));
- cut_lists[nlists-1].startpos = s;
- cut_lists[nlists-1].endpos = e;
- }
-
- /* make sure we got some cut positions out of all that */
- if (nlists == 0)
- bb_error_msg_and_die("missing list of positions");
+ char *line;
+ unsigned linenum = 0; /* keep these zero-based to be consistent */
- /* now that the lists are parsed, we need to sort them to make life easier
- * on us when it comes time to print the chars / fields / lines */
- qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
-
-}
+ /* go through every line in the file */
+ while ((line = xmalloc_fgetline(file)) != NULL) {
+ /* set up a list so we can keep track of what's been printed */
+ int linelen = strlen(line);
+ char *printed = xzalloc(linelen + 1);
+ char *orig_line = line;
+ unsigned cl_pos = 0;
+ int spos;
-static void cut_line_by_chars(const char *line)
-{
- int c, l;
- /* set up a list so we can keep track of what's been printed */
- char *printed = xcalloc(strlen(line), sizeof(char));
-
- /* print the chars specified in each cut list */
- for (c = 0; c < nlists; c++) {
- l = cut_lists[c].startpos;
- while (l < strlen(line)) {
- if (!printed[l]) {
- putchar(line[l]);
- printed[l] = 'X';
+ /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
+ if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) {
+ /* print the chars specified in each cut list */
+ for (; cl_pos < nlists; cl_pos++) {
+ spos = cut_lists[cl_pos].startpos;
+ while (spos < linelen) {
+ if (!printed[spos]) {
+ printed[spos] = 'X';
+ putchar(line[spos]);
+ }
+ spos++;
+ if (spos > cut_lists[cl_pos].endpos
+ /* NON_RANGE is -1, so if below is true,
+ * the above was true too (spos is >= 0) */
+ /* || cut_lists[cl_pos].endpos == NON_RANGE */
+ ) {
+ break;
+ }
+ }
+ }
+ } else if (delim == '\n') { /* cut by lines */
+ spos = cut_lists[cl_pos].startpos;
+
+ /* get out if we have no more lists to process or if the lines
+ * are lower than what we're interested in */
+ if (((int)linenum < spos) || (cl_pos >= nlists))
+ goto next_line;
+
+ /* if the line we're looking for is lower than the one we were
+ * passed, it means we displayed it already, so move on */
+ while (spos < (int)linenum) {
+ spos++;
+ /* go to the next list if we're at the end of this one */
+ if (spos > cut_lists[cl_pos].endpos
+ || cut_lists[cl_pos].endpos == NON_RANGE
+ ) {
+ cl_pos++;
+ /* get out if there's no more lists to process */
+ if (cl_pos >= nlists)
+ goto next_line;
+ spos = cut_lists[cl_pos].startpos;
+ /* get out if the current line is lower than the one
+ * we just became interested in */
+ if ((int)linenum < spos)
+ goto next_line;
+ }
}
- l++;
- if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos)
- break;
- }
- }
- putchar('\n'); /* cuz we were handed a chomped line */
- free(printed);
-}
-
-static void cut_line_by_fields(char *line)
-{
- int c, f;
- int ndelim = -1; /* zero-based / one-based problem */
- int nfields_printed = 0;
- char *field = NULL;
- char d[2] = { delim, 0 };
- char *printed;
-
- /* test the easy case first: does this line contain any delimiters? */
- if (strchr(line, delim) == NULL) {
- if (!supress_non_delimited_lines)
+ /* If we made it here, it means we've found the line we're
+ * looking for, so print it */
puts(line);
- return;
- }
-
- /* set up a list so we can keep track of what's been printed */
- printed = xcalloc(strlen(line), sizeof(char));
-
- /* process each list on this line, for as long as we've got a line to process */
- for (c = 0; c < nlists && line; c++) {
- f = cut_lists[c].startpos;
- do {
-
- /* find the field we're looking for */
- while (line && ndelim < f) {
- field = strsep(&line, d);
- ndelim++;
+ goto next_line;
+ } else { /* cut by fields */
+ int ndelim = -1; /* zero-based / one-based problem */
+ int nfields_printed = 0;
+ char *field = NULL;
+ const char delimiter[2] = { delim, 0 };
+
+ /* does this line contain any delimiters? */
+ if (strchr(line, delim) == NULL) {
+ if (!(option_mask32 & CUT_OPT_SUPPRESS_FLGS))
+ puts(line);
+ goto next_line;
}
- /* we found it, and it hasn't been printed yet */
- if (field && ndelim == f && !printed[ndelim]) {
- /* if this isn't our first time through, we need to print the
- * delimiter after the last field that was printed */
- if (nfields_printed > 0)
- putchar(delim);
- fputs(field, stdout);
- printed[ndelim] = 'X';
- nfields_printed++;
+ /* process each list on this line, for as long as we've got
+ * a line to process */
+ for (; cl_pos < nlists && line; cl_pos++) {
+ spos = cut_lists[cl_pos].startpos;
+ do {
+ /* find the field we're looking for */
+ while (line && ndelim < spos) {
+ field = strsep(&line, delimiter);
+ ndelim++;
+ }
+
+ /* we found it, and it hasn't been printed yet */
+ if (field && ndelim == spos && !printed[ndelim]) {
+ /* if this isn't our first time through, we need to
+ * print the delimiter after the last field that was
+ * printed */
+ if (nfields_printed > 0)
+ putchar(delim);
+ fputs(field, stdout);
+ printed[ndelim] = 'X';
+ nfields_printed++; /* shouldn't overflow.. */
+ }
+
+ spos++;
+
+ /* keep going as long as we have a line to work with,
+ * this is a list, and we're not at the end of that
+ * list */
+ } while (spos <= cut_lists[cl_pos].endpos && line
+ && cut_lists[cl_pos].endpos != NON_RANGE);
}
-
- f++;
-
- /* keep going as long as we have a line to work with, this is a
- * list, and we're not at the end of that list */
- } while (line && cut_lists[c].endpos != NON_RANGE && f <= cut_lists[c].endpos);
- }
-
- /* if we printed anything at all, we need to finish it with a newline cuz
- * we were handed a chomped line */
- putchar('\n');
-
- free(printed);
-}
-
-
-static void cut_file_by_lines(const char *line, unsigned int linenum)
-{
- static int c = 0;
- static int l = -1;
-
- /* I can't initialize this above cuz the "initializer isn't
- * constant" *sigh* */
- if (l == -1)
- l = cut_lists[c].startpos;
-
- /* get out if we have no more lists to process or if the lines are lower
- * than what we're interested in */
- if (c >= nlists || linenum < l)
- return;
-
- /* if the line we're looking for is lower than the one we were passed, it
- * means we displayed it already, so move on */
- while (l < linenum) {
- l++;
- /* move on to the next list if we're at the end of this one */
- if (cut_lists[c].endpos == NON_RANGE || l > cut_lists[c].endpos) {
- c++;
- /* get out if there's no more lists to process */
- if (c >= nlists)
- return;
- l = cut_lists[c].startpos;
- /* get out if the current line is lower than the one we just became
- * interested in */
- if (linenum < l)
- return;
- }
- }
-
- /* If we made it here, it means we've found the line we're looking for, so print it */
- puts(line);
-}
-
-
-/*
- * snippy-snip
- */
-static void cut_file(FILE *file)
-{
- char *line = NULL;
- unsigned int linenum = 0; /* keep these zero-based to be consistent */
-
- /* go through every line in the file */
- while ((line = bb_get_chomped_line_from_file(file)) != NULL) {
-
- /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
- if ((part & (OPT_CHAR_FLGS | OPT_BYTE_FLGS)))
- cut_line_by_chars(line);
-
- /* cut based on fields */
- else {
- if (delim == '\n')
- cut_file_by_lines(line, linenum);
- else
- cut_line_by_fields(line);
}
-
+ /* if we printed anything at all, we need to finish it with a
+ * newline cuz we were handed a chomped line */
+ putchar('\n');
+ next_line:
linenum++;
- free(line);
+ free(printed);
+ free(orig_line);
}
}
-
-extern int cut_main(int argc, char **argv)
+int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int cut_main(int argc UNUSED_PARAM, char **argv)
{
- unsigned long opt;
- char *sopt, *sdopt;
-
- bb_opt_complementaly = "b~bcf:c~bcf:f~bcf";
- opt = bb_getopt_ulflags(argc, argv, optstring, &sopt, &sopt, &sopt, &sdopt);
- part = opt & (OPT_BYTE_FLGS|OPT_CHAR_FLGS|OPT_FIELDS_FLGS);
- if(part == 0)
- bb_error_msg_and_die("you must specify a list of bytes, characters, or fields");
- if(opt & 0x80000000UL)
- bb_error_msg_and_die("only one type of list may be specified");
- parse_lists(sopt);
- if((opt & (OPT_DELIM_FLGS))) {
- if (strlen(sdopt) > 1) {
+ /* growable array holding a series of lists */
+ struct cut_list *cut_lists = NULL;
+ unsigned nlists = 0; /* number of elements in above list */
+ char delim = '\t'; /* delimiter, default is tab */
+ char *sopt, *ltok;
+ unsigned opt;
+
+ opt_complementary = "b--bcf:c--bcf:f--bcf";
+ opt = getopt32(argv, optstring, &sopt, &sopt, &sopt, &ltok);
+// argc -= optind;
+ argv += optind;
+ if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
+ bb_error_msg_and_die("expected a list of bytes, characters, or fields");
+
+ if (opt & CUT_OPT_DELIM_FLGS) {
+ if (ltok[0] && ltok[1]) { /* more than 1 char? */
bb_error_msg_and_die("the delimiter must be a single character");
}
- delim = sdopt[0];
+ delim = ltok[0];
}
- supress_non_delimited_lines = opt & OPT_SUPRESS_FLGS;
/* non-field (char or byte) cutting has some special handling */
- if (part != OPT_FIELDS_FLGS) {
- if (supress_non_delimited_lines) {
- bb_error_msg_and_die("suppressing non-delimited lines makes sense"
- " only when operating on fields");
+ if (!(opt & CUT_OPT_FIELDS_FLGS)) {
+ static const char _op_on_field[] ALIGN1 = " only when operating on fields";
+
+ if (opt & CUT_OPT_SUPPRESS_FLGS) {
+ bb_error_msg_and_die
+ ("suppressing non-delimited lines makes sense%s",
+ _op_on_field);
}
if (delim != '\t') {
- bb_error_msg_and_die("a delimiter may be specified only when operating on fields");
+ bb_error_msg_and_die
+ ("a delimiter may be specified%s", _op_on_field);
}
}
- /* argv[(optind)..(argc-1)] should be names of file to process. If no
- * files were specified or '-' was specified, take input from stdin.
- * Otherwise, we process all the files specified. */
- if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) {
- cut_file(stdin);
- }
- else {
- int i;
- FILE *file;
- for (i = optind; i < argc; i++) {
- file = bb_wfopen(argv[i], "r");
- if(file) {
- cut_file(file);
- fclose(file);
+ /*
+ * parse list and put values into startpos and endpos.
+ * valid list formats: N, N-, N-M, -M
+ * more than one list can be separated by commas
+ */
+ {
+ char *ntok;
+ int s = 0, e = 0;
+
+ /* take apart the lists, one by one (they are separated with commas) */
+ while ((ltok = strsep(&sopt, ",")) != NULL) {
+
+ /* it's actually legal to pass an empty list */
+ if (!ltok[0])
+ continue;
+
+ /* get the start pos */
+ ntok = strsep(&ltok, "-");
+ if (!ntok[0]) {
+ s = BOL;
+ } else {
+ s = xatoi_u(ntok);
+ /* account for the fact that arrays are zero based, while
+ * the user expects the first char on the line to be char #1 */
+ if (s != 0)
+ s--;
+ }
+
+ /* get the end pos */
+ if (ltok == NULL) {
+ e = NON_RANGE;
+ } else if (!ltok[0]) {
+ e = EOL;
+ } else {
+ e = xatoi_u(ltok);
+ /* if the user specified and end position of 0,
+ * that means "til the end of the line" */
+ if (e == 0)
+ e = EOL;
+ e--; /* again, arrays are zero based, lines are 1 based */
+ if (e == s)
+ e = NON_RANGE;
}
+
+ /* add the new list */
+ cut_lists = xrealloc_vector(cut_lists, 4, nlists);
+ /* NB: startpos is always >= 0,
+ * while endpos may be = NON_RANGE (-1) */
+ cut_lists[nlists].startpos = s;
+ cut_lists[nlists].endpos = e;
+ nlists++;
}
+
+ /* make sure we got some cut positions out of all that */
+ if (nlists == 0)
+ bb_error_msg_and_die("missing list of positions");
+
+ /* now that the lists are parsed, we need to sort them to make life
+ * easier on us when it comes time to print the chars / fields / lines
+ */
+ qsort(cut_lists, nlists, sizeof(struct cut_list), cmpfunc);
}
- return EXIT_SUCCESS;
+ {
+ int retval = EXIT_SUCCESS;
+
+ if (!*argv)
+ *--argv = (char *)"-";
+
+ do {
+ FILE *file = fopen_or_warn_stdin(*argv);
+ if (!file) {
+ retval = EXIT_FAILURE;
+ continue;
+ }
+ cut_file(file, delim, cut_lists, nlists);
+ fclose_if_not_stdin(file);
+ } while (*++argv);
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(cut_lists);
+ fflush_stdout_and_exit(retval);
+ }
}
diff --git a/release/src/router/busybox/coreutils/date.c b/release/src/router/busybox/coreutils/date.c
index 7d14ec32..177b7d07 100644
--- a/release/src/router/busybox/coreutils/date.c
+++ b/release/src/router/busybox/coreutils/date.c
@@ -3,223 +3,181 @@
* Mini date implementation for busybox
*
* by Matthew Grant <grantma@anathoth.gen.nz>
- *
- * iso-format handling added by Robert Griebl <griebl@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * iso-format handling added by Robert Griebl <griebl@gmx.de>
+ * bugfixes and cleanup by Bernhard Reutner-Fischer
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include "busybox.h"
-
+#include "libbb.h"
-/* This 'date' command supports only 2 time setting formats,
+/* This 'date' command supports only 2 time setting formats,
all the GNU strftime stuff (its in libc, lets use it),
- setting time using UTC and displaying int, as well as
- an RFC 822 complient date output for shell scripting
+ setting time using UTC and displaying it, as well as
+ an RFC 2822 compliant date output for shell scripting
mail commands */
/* Input parsing code is always bulky - used heavy duty libc stuff as
much as possible, missed out a lot of bounds checking */
-/* Default input handling to save suprising some people */
-
-static struct tm *date_conv_time(struct tm *tm_time, const char *t_string)
-{
- int nr;
-
- nr = sscanf(t_string, "%2d%2d%2d%2d%d", &(tm_time->tm_mon),
- &(tm_time->tm_mday), &(tm_time->tm_hour), &(tm_time->tm_min),
- &(tm_time->tm_year));
-
- if (nr < 4 || nr > 5) {
- bb_error_msg_and_die(bb_msg_invalid_date, t_string);
- }
-
- /* correct for century - minor Y2K problem here? */
- if (tm_time->tm_year >= 1900) {
- tm_time->tm_year -= 1900;
- }
- /* adjust date */
- tm_time->tm_mon -= 1;
-
- return (tm_time);
-
-}
+/* Default input handling to save surprising some people */
-/* The new stuff for LRP */
+#define DATE_OPT_RFC2822 0x01
+#define DATE_OPT_SET 0x02
+#define DATE_OPT_UTC 0x04
+#define DATE_OPT_DATE 0x08
+#define DATE_OPT_REFERENCE 0x10
+#define DATE_OPT_TIMESPEC 0x20
+#define DATE_OPT_HINT 0x40
-static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string)
+static void maybe_set_utc(int opt)
{
- struct tm t;
-
- /* Parse input and assign appropriately to tm_time */
-
- if (t =
- *tm_time, sscanf(t_string, "%d:%d:%d", &t.tm_hour, &t.tm_min,
- &t.tm_sec) == 3) {
- /* no adjustments needed */
- } else if (t =
- *tm_time, sscanf(t_string, "%d:%d", &t.tm_hour,
- &t.tm_min) == 2) {
- /* no adjustments needed */
- } else if (t =
- *tm_time, sscanf(t_string, "%d.%d-%d:%d:%d", &t.tm_mon,
- &t.tm_mday, &t.tm_hour, &t.tm_min,
- &t.tm_sec) == 5) {
- /* Adjust dates from 1-12 to 0-11 */
- t.tm_mon -= 1;
- } else if (t =
- *tm_time, sscanf(t_string, "%d.%d-%d:%d", &t.tm_mon,
- &t.tm_mday, &t.tm_hour, &t.tm_min) == 4) {
- /* Adjust dates from 1-12 to 0-11 */
- t.tm_mon -= 1;
- } else if (t =
- *tm_time, sscanf(t_string, "%d.%d.%d-%d:%d:%d", &t.tm_year,
- &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min,
- &t.tm_sec) == 6) {
- t.tm_year -= 1900; /* Adjust years */
- t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
- } else if (t =
- *tm_time, sscanf(t_string, "%d.%d.%d-%d:%d", &t.tm_year,
- &t.tm_mon, &t.tm_mday, &t.tm_hour,
- &t.tm_min) == 5) {
- t.tm_year -= 1900; /* Adjust years */
- t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
- } else {
- bb_error_msg_and_die(bb_msg_invalid_date, t_string);
- }
- *tm_time = t;
- return (tm_time);
+ if (opt & DATE_OPT_UTC)
+ putenv((char*)"TZ=UTC0");
}
-
-int date_main(int argc, char **argv)
+int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int date_main(int argc UNUSED_PARAM, char **argv)
{
- char *date_str = NULL;
- char *date_fmt = NULL;
- char *t_buff;
- int set_time;
- int rfc822;
- int utc;
- int use_arg = 0;
- time_t tm;
- unsigned long opt;
struct tm tm_time;
-
-#ifdef CONFIG_FEATURE_DATE_ISOFMT
- int ifmt = 0;
- char *isofmt_arg;
-
-# define GETOPT_ISOFMT "I::"
-#else
-# define GETOPT_ISOFMT
-#endif
- bb_opt_complementaly = "d~ds:s~ds";
- opt = bb_getopt_ulflags(argc, argv, "Rs:ud:" GETOPT_ISOFMT,
- &date_str, &date_str
-#ifdef CONFIG_FEATURE_DATE_ISOFMT
- , &isofmt_arg
-#endif
- );
- rfc822 = opt & 1;
- set_time = opt & 2;
- utc = opt & 4;
- if(utc) {
- if (putenv("TZ=UTC0") != 0)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
- }
- use_arg = opt & 8;
- if(opt & 0x80000000UL)
+ time_t tm;
+ unsigned opt;
+ int ifmt = -1;
+ char *date_str;
+ char *fmt_dt2str;
+ char *fmt_str2dt;
+ char *filename;
+ char *isofmt_arg = NULL;
+
+ opt_complementary = "d--s:s--d"
+ USE_FEATURE_DATE_ISOFMT(":R--I:I--R");
+ opt = getopt32(argv, "Rs:ud:r:"
+ USE_FEATURE_DATE_ISOFMT("I::D:"),
+ &date_str, &date_str, &filename
+ USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
+ argv += optind;
+ maybe_set_utc(opt);
+
+ if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) {
+ ifmt = 0; /* default is date */
+ if (isofmt_arg) {
+ static const char isoformats[] ALIGN1 =
+ "date\0""hours\0""minutes\0""seconds\0";
+ ifmt = index_in_strings(isoformats, isofmt_arg);
+ if (ifmt < 0)
bb_show_usage();
-#ifdef CONFIG_FEATURE_DATE_ISOFMT
- if(opt & 16) {
- if (!isofmt_arg)
- ifmt = 1;
- else {
- int ifmt_len = bb_strlen(isofmt_arg);
-
- if ((ifmt_len <= 4)
- && (strncmp(isofmt_arg, "date", ifmt_len) == 0)) {
- ifmt = 1;
- } else if ((ifmt_len <= 5)
- && (strncmp(isofmt_arg, "hours", ifmt_len) == 0)) {
- ifmt = 2;
- } else if ((ifmt_len <= 7)
- && (strncmp(isofmt_arg, "minutes", ifmt_len) == 0)) {
- ifmt = 3;
- } else if ((ifmt_len <= 7)
- && (strncmp(isofmt_arg, "seconds", ifmt_len) == 0)) {
- ifmt = 4;
- }
- }
- if (!ifmt) {
- bb_show_usage();
}
}
-#endif
- if ((date_fmt == NULL) && (optind < argc) && (argv[optind][0] == '+')) {
- date_fmt = &argv[optind][1]; /* Skip over the '+' */
- } else if (date_str == NULL) {
- set_time = 1;
- date_str = argv[optind];
+ fmt_dt2str = NULL;
+ if (argv[0] && argv[0][0] == '+') {
+ fmt_dt2str = &argv[0][1]; /* Skip over the '+' */
+ argv++;
+ }
+ if (!(opt & (DATE_OPT_SET | DATE_OPT_DATE))) {
+ opt |= DATE_OPT_SET;
+ date_str = argv[0]; /* can be NULL */
+ if (date_str)
+ argv++;
}
+ if (*argv)
+ bb_show_usage();
/* Now we have parsed all the information except the date format
which depends on whether the clock is being set or read */
- time(&tm);
+ if (opt & DATE_OPT_REFERENCE) {
+ struct stat statbuf;
+ xstat(filename, &statbuf);
+ tm = statbuf.st_mtime;
+ } else
+ time(&tm);
memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
- /* Zero out fields - take her back to midnight! */
+
+ /* If date string is given, update tm_time, and maybe set date */
if (date_str != NULL) {
+ /* Zero out fields - take her back to midnight! */
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
tm_time.tm_hour = 0;
- }
-
- /* Process any date input to UNIX time since 1 Jan 1970 */
- if (date_str != NULL) {
- if (strchr(date_str, ':') != NULL) {
- date_conv_ftime(&tm_time, date_str);
+ /* Process any date input to UNIX time since 1 Jan 1970 */
+ if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) {
+ if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
} else {
- date_conv_time(&tm_time, date_str);
+ char end = '\0';
+ const char *last_colon = strrchr(date_str, ':');
+
+ if (last_colon != NULL) {
+ /* Parse input and assign appropriately to tm_time */
+
+ if (sscanf(date_str, "%u:%u%c",
+ &tm_time.tm_hour,
+ &tm_time.tm_min,
+ &end) >= 2) {
+ /* no adjustments needed */
+ } else if (sscanf(date_str, "%u.%u-%u:%u%c",
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 4) {
+ /* Adjust dates from 1-12 to 0-11 */
+ tm_time.tm_mon -= 1;
+ } else if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time.tm_year,
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 5) {
+ tm_time.tm_year -= 1900; /* Adjust years */
+ tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
+ } else if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time.tm_year,
+ &tm_time.tm_mon, &tm_time.tm_mday,
+ &tm_time.tm_hour, &tm_time.tm_min,
+ &end) >= 5) {
+ tm_time.tm_year -= 1900; /* Adjust years */
+ tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */
+//TODO: coreutils 6.9 also accepts "YYYY-MM-DD HH" (no minutes)
+ } else {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
+ if (end == ':') {
+ if (sscanf(last_colon + 1, "%u%c", &tm_time.tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ } else {
+ if (sscanf(date_str, "%2u%2u%2u%2u%u%c", &tm_time.tm_mon,
+ &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min,
+ &tm_time.tm_year, &end) < 4)
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ /* correct for century - minor Y2K problem here? */
+ if (tm_time.tm_year >= 1900) {
+ tm_time.tm_year -= 1900;
+ }
+ /* adjust date */
+ tm_time.tm_mon -= 1;
+ if (end == '.') {
+ if (sscanf(strchr(date_str, '.') + 1, "%u%c",
+ &tm_time.tm_sec, &end) == 1)
+ end = '\0';
+ /* else end != NUL and we error out */
+ }
+ }
+ if (end != '\0') {
+ bb_error_msg_and_die(bb_msg_invalid_date, date_str);
+ }
}
-
/* Correct any day of week and day of year etc. fields */
tm_time.tm_isdst = -1; /* Be sure to recheck dst. */
tm = mktime(&tm_time);
if (tm < 0) {
bb_error_msg_and_die(bb_msg_invalid_date, date_str);
}
- if (utc && (putenv("TZ=UTC0") != 0)) {
- bb_error_msg_and_die(bb_msg_memory_exhausted);
- }
+ maybe_set_utc(opt);
/* if setting time, set it */
- if (set_time && (stime(&tm) < 0)) {
+ if ((opt & DATE_OPT_SET) && stime(&tm) < 0) {
bb_perror_msg("cannot set date");
}
}
@@ -227,49 +185,55 @@ int date_main(int argc, char **argv)
/* Display output */
/* Deal with format string */
- if (date_fmt == NULL) {
-#ifdef CONFIG_FEATURE_DATE_ISOFMT
- switch (ifmt) {
- case 4:
- date_fmt = utc ? "%Y-%m-%dT%H:%M:%SZ" : "%Y-%m-%dT%H:%M:%S%z";
- break;
- case 3:
- date_fmt = utc ? "%Y-%m-%dT%H:%MZ" : "%Y-%m-%dT%H:%M%z";
- break;
- case 2:
- date_fmt = utc ? "%Y-%m-%dT%HZ" : "%Y-%m-%dT%H%z";
- break;
- case 1:
- date_fmt = "%Y-%m-%d";
- break;
- case 0:
- default:
-#endif
- date_fmt =
- (rfc822
- ? (utc ? "%a, %e %b %Y %H:%M:%S GMT" :
- "%a, %e %b %Y %H:%M:%S %z") : "%a %b %e %H:%M:%S %Z %Y");
-
-#ifdef CONFIG_FEATURE_DATE_ISOFMT
- break;
- }
-#endif
- } else if (*date_fmt == '\0') {
- /* Imitate what GNU 'date' does with NO format string! */
- printf("\n");
- return EXIT_SUCCESS;
+ if (fmt_dt2str == NULL) {
+ int i;
+ fmt_dt2str = xzalloc(32);
+ if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) {
+ strcpy(fmt_dt2str, "%Y-%m-%d");
+ if (ifmt > 0) {
+ i = 8;
+ fmt_dt2str[i++] = 'T';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'H';
+ if (ifmt > 1) {
+ fmt_dt2str[i++] = ':';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'M';
+ if (ifmt > 2) {
+ fmt_dt2str[i++] = ':';
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i++] = 'S';
+ }
+ }
+ format_utc:
+ fmt_dt2str[i++] = '%';
+ fmt_dt2str[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z';
+ }
+ } else if (opt & DATE_OPT_RFC2822) {
+ /* Undo busybox.c for date -R */
+ if (ENABLE_LOCALE_SUPPORT)
+ setlocale(LC_TIME, "C");
+ strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S ");
+ i = 22;
+ goto format_utc;
+ } else /* default case */
+ fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
}
- /* Handle special conversions */
+#define date_buf bb_common_bufsiz1
+ if (*fmt_dt2str == '\0') {
+ /* With no format string, just print a blank line */
+ date_buf[0] = '\0';
+ } else {
+ /* Handle special conversions */
+ if (strncmp(fmt_dt2str, "%f", 2) == 0) {
+ fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";
+ }
- if (strncmp(date_fmt, "%f", 2) == 0) {
- date_fmt = "%Y.%m.%d-%H:%M:%S";
+ /* Generate output string */
+ strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time);
}
-
- /* Print OUTPUT (after ALL that!) */
- t_buff = xmalloc(201);
- strftime(t_buff, 200, date_fmt, &tm_time);
- puts(t_buff);
+ puts(date_buf);
return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/coreutils/dd.c b/release/src/router/busybox/coreutils/dd.c
index cd97b24e..38dacc71 100644
--- a/release/src/router/busybox/coreutils/dd.c
+++ b/release/src/router/busybox/coreutils/dd.c
@@ -5,199 +5,351 @@
*
* Copyright (C) 2000,2001 Matt Kraai
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+enum {
+ ifd = STDIN_FILENO,
+ ofd = STDOUT_FILENO,
+};
+
static const struct suffix_mult dd_suffixes[] = {
{ "c", 1 },
{ "w", 2 },
{ "b", 512 },
{ "kD", 1000 },
{ "k", 1024 },
+ { "K", 1024 }, /* compat with coreutils dd */
{ "MD", 1000000 },
{ "M", 1048576 },
{ "GD", 1000000000 },
{ "G", 1073741824 },
- { NULL, 0 }
+ { }
+};
+
+struct globals {
+ off_t out_full, out_part, in_full, in_part;
};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+/* We have to zero it out because of NOEXEC */
+#define INIT_G() memset(&G, 0, sizeof(G))
+
+
+static void dd_output_status(int UNUSED_PARAM cur_signal)
+{
+ /* Deliberately using %u, not %d */
+ fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n"
+ "%"OFF_FMT"u+%"OFF_FMT"u records out\n",
+ G.in_full, G.in_part,
+ G.out_full, G.out_part);
+}
+
+static ssize_t full_write_or_warn(const void *buf, size_t len,
+ const char *const filename)
+{
+ ssize_t n = full_write(ofd, buf, len);
+ if (n < 0)
+ bb_perror_msg("writing '%s'", filename);
+ return n;
+}
+
+static bool write_and_stats(const void *buf, size_t len, size_t obs,
+ const char *filename)
+{
+ ssize_t n = full_write_or_warn(buf, len, filename);
+ if (n < 0)
+ return 1;
+ if ((size_t)n == obs)
+ G.out_full++;
+ else if (n) /* > 0 */
+ G.out_part++;
+ return 0;
+}
-int dd_main(int argc, char **argv)
+#if ENABLE_LFS
+#define XATOU_SFX xatoull_sfx
+#else
+#define XATOU_SFX xatoul_sfx
+#endif
+
+int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dd_main(int argc UNUSED_PARAM, char **argv)
{
- size_t out_full = 0;
- size_t out_part = 0;
- size_t in_full = 0;
- size_t in_part = 0;
- size_t count = -1;
- size_t bs = 512;
- ssize_t n;
- off_t seek = 0;
- off_t skip = 0;
- int sync_flag = FALSE;
- int noerror = FALSE;
- int trunc = TRUE;
- int oflag;
- int ifd;
- int ofd;
- int i;
- const char *infile = NULL;
- const char *outfile = NULL;
- char *buf;
-
- for (i = 1; i < argc; i++) {
- if (strncmp("bs=", argv[i], 3) == 0)
- bs = bb_xparse_number(argv[i]+3, dd_suffixes);
- else if (strncmp("count=", argv[i], 6) == 0)
- count = bb_xparse_number(argv[i]+6, dd_suffixes);
- else if (strncmp("seek=", argv[i], 5) == 0)
- seek = bb_xparse_number(argv[i]+5, dd_suffixes);
- else if (strncmp("skip=", argv[i], 5) == 0)
- skip = bb_xparse_number(argv[i]+5, dd_suffixes);
- else if (strncmp("if=", argv[i], 3) == 0)
- infile = argv[i]+3;
- else if (strncmp("of=", argv[i], 3) == 0)
- outfile = argv[i]+3;
- else if (strncmp("conv=", argv[i], 5) == 0) {
- buf = argv[i]+5;
+ enum {
+ /* Must be in the same order as OP_conv_XXX! */
+ /* (see "flags |= (1 << what)" below) */
+ FLAG_NOTRUNC = 1 << 0,
+ FLAG_SYNC = 1 << 1,
+ FLAG_NOERROR = 1 << 2,
+ FLAG_FSYNC = 1 << 3,
+ /* end of conv flags */
+ FLAG_TWOBUFS = 1 << 4,
+ FLAG_COUNT = 1 << 5,
+ };
+ static const char keywords[] ALIGN1 =
+ "bs\0""count\0""seek\0""skip\0""if\0""of\0"
+#if ENABLE_FEATURE_DD_IBS_OBS
+ "ibs\0""obs\0""conv\0"
+#endif
+ ;
+#if ENABLE_FEATURE_DD_IBS_OBS
+ static const char conv_words[] ALIGN1 =
+ "notrunc\0""sync\0""noerror\0""fsync\0";
+#endif
+ enum {
+ OP_bs = 0,
+ OP_count,
+ OP_seek,
+ OP_skip,
+ OP_if,
+ OP_of,
+#if ENABLE_FEATURE_DD_IBS_OBS
+ OP_ibs,
+ OP_obs,
+ OP_conv,
+ /* Must be in the same order as FLAG_XXX! */
+ OP_conv_notrunc = 0,
+ OP_conv_sync,
+ OP_conv_noerror,
+ OP_conv_fsync,
+ /* Unimplemented conv=XXX: */
+ //nocreat do not create the output file
+ //excl fail if the output file already exists
+ //fdatasync physically write output file data before finishing
+ //swab swap every pair of input bytes
+ //lcase change upper case to lower case
+ //ucase change lower case to upper case
+ //block pad newline-terminated records with spaces to cbs-size
+ //unblock replace trailing spaces in cbs-size records with newline
+ //ascii from EBCDIC to ASCII
+ //ebcdic from ASCII to EBCDIC
+ //ibm from ASCII to alternate EBCDIC
+#endif
+ };
+ int exitcode = EXIT_FAILURE;
+ size_t ibs = 512, obs = 512;
+ ssize_t n, w;
+ char *ibuf, *obuf;
+ /* And these are all zeroed at once! */
+ struct {
+ int flags;
+ size_t oc;
+ off_t count;
+ off_t seek, skip;
+ const char *infile, *outfile;
+ } Z;
+#define flags (Z.flags )
+#define oc (Z.oc )
+#define count (Z.count )
+#define seek (Z.seek )
+#define skip (Z.skip )
+#define infile (Z.infile )
+#define outfile (Z.outfile)
+
+ memset(&Z, 0, sizeof(Z));
+ INIT_G();
+ //fflush(NULL); - is this needed because of NOEXEC?
+
+#if ENABLE_FEATURE_DD_SIGNAL_HANDLING
+ signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status);
+#endif
+
+ for (n = 1; argv[n]; n++) {
+ int what;
+ char *val;
+ char *arg = argv[n];
+
+#if ENABLE_DESKTOP
+ /* "dd --". NB: coreutils 6.9 will complain if they see
+ * more than one of them. We wouldn't. */
+ if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0')
+ continue;
+#endif
+ val = strchr(arg, '=');
+ if (val == NULL)
+ bb_show_usage();
+ *val = '\0';
+ what = index_in_strings(keywords, arg);
+ if (what < 0)
+ bb_show_usage();
+ /* *val = '='; - to preserve ps listing? */
+ val++;
+#if ENABLE_FEATURE_DD_IBS_OBS
+ if (what == OP_ibs) {
+ /* Must fit into positive ssize_t */
+ ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_obs) {
+ obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_conv) {
while (1) {
- if (strncmp("notrunc", buf, 7) == 0) {
- trunc = FALSE;
- buf += 7;
- } else if (strncmp("sync", buf, 4) == 0) {
- sync_flag = TRUE;
- buf += 4;
- } else if (strncmp("noerror", buf, 7) == 0) {
- noerror = TRUE;
- buf += 7;
- } else {
- bb_error_msg_and_die("invalid conversion `%s'", argv[i]+5);
- }
- if (buf[0] == '\0')
+ /* find ',', replace them with NUL so we can use val for
+ * index_in_strings() without copying.
+ * We rely on val being non-null, else strchr would fault.
+ */
+ arg = strchr(val, ',');
+ if (arg)
+ *arg = '\0';
+ what = index_in_strings(conv_words, val);
+ if (what < 0)
+ bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv");
+ flags |= (1 << what);
+ if (!arg) /* no ',' left, so this was the last specifier */
break;
- if (buf[0] == ',')
- buf++;
+ /* *arg = ','; - to preserve ps listing? */
+ val = arg + 1; /* skip this keyword and ',' */
}
- } else
- bb_show_usage();
- }
-
- buf = xmalloc(bs);
+ continue; /* we trashed 'what', can't fall through */
+ }
+#endif
+ if (what == OP_bs) {
+ ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes);
+ /*continue;*/
+ }
+ /* These can be large: */
+ if (what == OP_count) {
+ flags |= FLAG_COUNT;
+ count = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_seek) {
+ seek = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_skip) {
+ skip = XATOU_SFX(val, dd_suffixes);
+ /*continue;*/
+ }
+ if (what == OP_if) {
+ infile = val;
+ /*continue;*/
+ }
+ if (what == OP_of) {
+ outfile = val;
+ /*continue;*/
+ }
+ } /* end of "for (argv[n])" */
- if (infile != NULL) {
- ifd = bb_xopen(infile, O_RDONLY);
- } else {
- ifd = STDIN_FILENO;
+//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
+ ibuf = obuf = xmalloc(ibs);
+ if (ibs != obs) {
+ flags |= FLAG_TWOBUFS;
+ obuf = xmalloc(obs);
+ }
+ if (infile != NULL)
+ xmove_fd(xopen(infile, O_RDONLY), ifd);
+ else {
infile = bb_msg_standard_input;
}
-
if (outfile != NULL) {
- oflag = O_WRONLY | O_CREAT;
+ int oflag = O_WRONLY | O_CREAT;
- if (!seek && trunc) {
+ if (!seek && !(flags & FLAG_NOTRUNC))
oflag |= O_TRUNC;
- }
- if ((ofd = open(outfile, oflag, 0666)) < 0) {
- bb_perror_msg_and_die("%s", outfile);
- }
+ xmove_fd(xopen(outfile, oflag), ofd);
- if (seek && trunc) {
- if (ftruncate(ofd, seek * bs) < 0) {
+ if (seek && !(flags & FLAG_NOTRUNC)) {
+ if (ftruncate(ofd, seek * obs) < 0) {
struct stat st;
- if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) ||
- S_ISDIR (st.st_mode)) {
- bb_perror_msg_and_die("%s", outfile);
- }
+ if (fstat(ofd, &st) < 0 || S_ISREG(st.st_mode) ||
+ S_ISDIR(st.st_mode))
+ goto die_outfile;
}
}
} else {
- ofd = STDOUT_FILENO;
outfile = bb_msg_standard_output;
}
-
if (skip) {
- if (lseek(ifd, skip * bs, SEEK_CUR) < 0) {
- bb_perror_msg_and_die("%s", infile);
+ if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
+ while (skip-- > 0) {
+ n = safe_read(ifd, ibuf, ibs);
+ if (n < 0)
+ goto die_infile;
+ if (n == 0)
+ break;
+ }
}
}
-
if (seek) {
- if (lseek(ofd, seek * bs, SEEK_CUR) < 0) {
- bb_perror_msg_and_die("%s", outfile);
- }
+ if (lseek(ofd, seek * obs, SEEK_CUR) < 0)
+ goto die_outfile;
}
- while (in_full + in_part != count) {
- if (noerror) {
- /* Pre-zero the buffer when doing the noerror thing */
- memset(buf, '\0', bs);
- }
- n = safe_read(ifd, buf, bs);
- if (n < 0) {
- if (noerror) {
- n = bs;
- bb_perror_msg("%s", infile);
- } else {
- bb_perror_msg_and_die("%s", infile);
- }
- }
- if (n == 0) {
+ while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
+ if (flags & FLAG_NOERROR) /* Pre-zero the buffer if conv=noerror */
+ memset(ibuf, 0, ibs);
+ n = safe_read(ifd, ibuf, ibs);
+ if (n == 0)
break;
- }
- if (n == bs) {
- in_full++;
- } else {
- in_part++;
- }
- if (sync_flag) {
- memset(buf + n, '\0', bs - n);
- n = bs;
- }
- n = bb_full_write(ofd, buf, n);
if (n < 0) {
- bb_perror_msg_and_die("%s", outfile);
+ if (!(flags & FLAG_NOERROR))
+ goto die_infile;
+ n = ibs;
+ bb_simple_perror_msg(infile);
}
- if (n == bs) {
- out_full++;
- } else {
- out_part++;
+ if ((size_t)n == ibs)
+ G.in_full++;
+ else {
+ G.in_part++;
+ if (flags & FLAG_SYNC) {
+ memset(ibuf + n, '\0', ibs - n);
+ n = ibs;
+ }
+ }
+ if (flags & FLAG_TWOBUFS) {
+ char *tmp = ibuf;
+ while (n) {
+ size_t d = obs - oc;
+
+ if (d > (size_t)n)
+ d = n;
+ memcpy(obuf + oc, tmp, d);
+ n -= d;
+ tmp += d;
+ oc += d;
+ if (oc == obs) {
+ if (write_and_stats(obuf, obs, obs, outfile))
+ goto out_status;
+ oc = 0;
+ }
+ }
+ } else if (write_and_stats(ibuf, n, obs, outfile))
+ goto out_status;
+
+ if (flags & FLAG_FSYNC) {
+ if (fsync(ofd) < 0)
+ goto die_outfile;
}
}
- if (close (ifd) < 0) {
- bb_perror_msg_and_die("%s", infile);
+ if (ENABLE_FEATURE_DD_IBS_OBS && oc) {
+ w = full_write_or_warn(obuf, oc, outfile);
+ if (w < 0) goto out_status;
+ if (w > 0) G.out_part++;
+ }
+ if (close(ifd) < 0) {
+ die_infile:
+ bb_simple_perror_msg_and_die(infile);
}
- if (close (ofd) < 0) {
- bb_perror_msg_and_die("%s", outfile);
+ if (close(ofd) < 0) {
+ die_outfile:
+ bb_simple_perror_msg_and_die(outfile);
}
- fprintf(stderr, "%ld+%ld records in\n%ld+%ld records out\n",
- (long)in_full, (long)in_part,
- (long)out_full, (long)out_part);
+ exitcode = EXIT_SUCCESS;
+ out_status:
+ dd_output_status(0);
- return EXIT_SUCCESS;
+ return exitcode;
}
diff --git a/release/src/router/busybox/coreutils/df.c b/release/src/router/busybox/coreutils/df.c
index 9c0d13f6..e9a865c1 100644
--- a/release/src/router/busybox/coreutils/df.c
+++ b/release/src/router/busybox/coreutils/df.c
@@ -2,107 +2,127 @@
/*
* Mini df implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
* based on original code by (I think) Bruce Perens <bruce@pixar.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* BB_AUDIT SUSv3 _NOT_ compliant -- options -P and -t missing. Also blocksize. */
+/* BB_AUDIT SUSv3 _NOT_ compliant -- option -t missing. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/df.html */
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
*
* Size reduction. Removed floating point dependency. Added error checking
- * on output. Output stats on 0-sized filesystems if specificly listed on
+ * on output. Output stats on 0-sized filesystems if specifically listed on
* the command line. Properly round *-blocks, Used, and Available quantities.
+ *
+ * Aug 28, 2008 Bernhard Reutner-Fischer
+ *
+ * Implement -P and -B; better coreutils compat; cleanup
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include <mntent.h>
#include <sys/vfs.h>
-#include "busybox.h"
+#include "libbb.h"
-#ifndef CONFIG_FEATURE_HUMAN_READABLE
-static long kscale(long b, long bs)
+#if !ENABLE_FEATURE_HUMAN_READABLE
+static unsigned long kscale(unsigned long b, unsigned long bs)
{
- return ( b * (long long) bs + KILOBYTE/2 ) / KILOBYTE;
+ return (b * (unsigned long long) bs + 1024/2) / 1024;
}
#endif
-extern int df_main(int argc, char **argv)
+int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int df_main(int argc, char **argv)
{
- long blocks_used;
- long blocks_percent_used;
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- unsigned long df_disp_hr = KILOBYTE;
-#endif
+ unsigned long blocks_used;
+ unsigned blocks_percent_used;
+ unsigned long df_disp_hr = 1024;
int status = EXIT_SUCCESS;
- unsigned long opt;
+ unsigned opt;
FILE *mount_table;
struct mntent *mount_entry;
struct statfs s;
- static const char hdr_1k[] = "1k-blocks"; /* default display is kilobytes */
- const char *disp_units_hdr = hdr_1k;
-
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- bb_opt_complementaly = "h-km:k-hm:m-hk";
- opt = bb_getopt_ulflags(argc, argv, "hmk");
- if(opt & 1) {
- df_disp_hr = 0;
- disp_units_hdr = " Size";
- }
- if(opt & 2) {
- df_disp_hr = MEGABYTE;
- disp_units_hdr = "1M-blocks";
+
+ enum {
+ OPT_KILO = (1 << 0),
+ OPT_POSIX = (1 << 1),
+ OPT_ALL = (1 << 2) * ENABLE_FEATURE_DF_FANCY,
+ OPT_INODE = (1 << 3) * ENABLE_FEATURE_DF_FANCY,
+ OPT_BSIZE = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
+ OPT_HUMAN = (1 << (2 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
+ OPT_MEGA = (1 << (3 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
+ };
+ const char *disp_units_hdr = NULL;
+ char *chp;
+
+#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
+ opt_complementary = "k-mB:m-Bk:B-km";
+#elif ENABLE_FEATURE_HUMAN_READABLE
+ opt_complementary = "k-m:m-k";
+#endif
+ opt = getopt32(argv, "kP"
+ USE_FEATURE_DF_FANCY("aiB:")
+ USE_FEATURE_HUMAN_READABLE("hm")
+ USE_FEATURE_DF_FANCY(, &chp));
+ if (opt & OPT_MEGA)
+ df_disp_hr = 1024*1024;
+
+ if (opt & OPT_BSIZE)
+ df_disp_hr = xatoul_range(chp, 1, ULONG_MAX); /* disallow 0 */
+
+ /* From the manpage of df from coreutils-6.10:
+ Disk space is shown in 1K blocks by default, unless the environment
+ variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used.
+ */
+ if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */
+ df_disp_hr = 512;
+
+ if (opt & OPT_HUMAN) {
+ df_disp_hr = 0;
+ disp_units_hdr = " Size";
}
+ if (opt & OPT_INODE)
+ disp_units_hdr = " Inodes";
+
+ if (disp_units_hdr == NULL) {
+#if ENABLE_FEATURE_HUMAN_READABLE
+ disp_units_hdr = xasprintf("%s-blocks",
+ make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)));
#else
- opt = bb_getopt_ulflags(argc, argv, "k");
+ disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr);
#endif
-
- bb_printf("Filesystem%11s%-15sUsed Available Use%% Mounted on\n",
- "", disp_units_hdr);
+ }
+ printf("Filesystem %-15sUsed Available %s Mounted on\n",
+ disp_units_hdr, (opt & OPT_POSIX) ? "Capacity" : "Use%");
mount_table = NULL;
argv += optind;
if (optind >= argc) {
- if (!(mount_table = setmntent(bb_path_mtab_file, "r"))) {
+ mount_table = setmntent(bb_path_mtab_file, "r");
+ if (!mount_table)
bb_perror_msg_and_die(bb_path_mtab_file);
- }
}
- do {
+ while (1) {
const char *device;
const char *mount_point;
if (mount_table) {
- if (!(mount_entry = getmntent(mount_table))) {
+ mount_entry = getmntent(mount_table);
+ if (!mount_entry) {
endmntent(mount_table);
break;
}
} else {
- if (!(mount_point = *argv++)) {
+ mount_point = *argv++;
+ if (!mount_point)
break;
- }
- if (!(mount_entry = find_mount_point(mount_point, bb_path_mtab_file))) {
- bb_error_msg("%s: can't find mount point.", mount_point);
- SET_ERROR:
+ mount_entry = find_mount_point(mount_point);
+ if (!mount_entry) {
+ bb_error_msg("%s: can't find mount point", mount_point);
+ set_error:
status = EXIT_FAILURE;
continue;
}
@@ -112,59 +132,65 @@ extern int df_main(int argc, char **argv)
mount_point = mount_entry->mnt_dir;
if (statfs(mount_point, &s) != 0) {
- bb_perror_msg("%s", mount_point);
- goto SET_ERROR;
+ bb_simple_perror_msg(mount_point);
+ goto set_error;
}
-
- if ((s.f_blocks > 0) || !mount_table){
+
+ if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {
+ if (opt & OPT_INODE) {
+ s.f_blocks = s.f_files;
+ s.f_bavail = s.f_bfree = s.f_ffree;
+ s.f_bsize = 1;
+
+ if (df_disp_hr)
+ df_disp_hr = 1;
+ }
blocks_used = s.f_blocks - s.f_bfree;
blocks_percent_used = 0;
if (blocks_used + s.f_bavail) {
- blocks_percent_used = (((long long) blocks_used) * 100
- + (blocks_used + s.f_bavail)/2
- ) / (blocks_used + s.f_bavail);
+ blocks_percent_used = (blocks_used * 100ULL
+ + (blocks_used + s.f_bavail)/2
+ ) / (blocks_used + s.f_bavail);
}
-
- if (strcmp(device, "rootfs") == 0) {
+
+ /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */
+ if (strcmp(device, "rootfs") == 0)
continue;
- } else if (strcmp(device, "/dev/root") == 0) {
+
+#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
+/* ... and also this is the only user of find_block_device */
+ if (strcmp(device, "/dev/root") == 0) {
/* Adjusts device to be the real root device,
* or leaves device alone if it can't find it */
- if ((device = find_real_root_device_name(device)) == NULL) {
- goto SET_ERROR;
+ device = find_block_device("/");
+ if (!device) {
+ goto set_error;
}
}
-
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- bb_printf("%-21s%9s ", device,
- make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
-
- bb_printf("%9s ",
- make_human_readable_str( (s.f_blocks - s.f_bfree),
- s.f_bsize, df_disp_hr));
-
- bb_printf("%9s %3ld%% %s\n",
- make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
- blocks_percent_used, mount_point);
+#endif
+
+ if (printf("\n%-20s" + 1, device) > 20)
+ printf("\n%-20s", "");
+#if ENABLE_FEATURE_HUMAN_READABLE
+ printf(" %9s ",
+ make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr));
+
+ printf(" %9s " + 1,
+ make_human_readable_str((s.f_blocks - s.f_bfree),
+ s.f_bsize, df_disp_hr));
+
+ printf("%9s %3u%% %s\n",
+ make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr),
+ blocks_percent_used, mount_point);
#else
- bb_printf("%-21s%9ld %9ld %9ld %3ld%% %s\n",
- device,
- kscale(s.f_blocks, s.f_bsize),
- kscale(s.f_blocks-s.f_bfree, s.f_bsize),
- kscale(s.f_bavail, s.f_bsize),
- blocks_percent_used, mount_point);
+ printf(" %9lu %9lu %9lu %3u%% %s\n",
+ kscale(s.f_blocks, s.f_bsize),
+ kscale(s.f_blocks - s.f_bfree, s.f_bsize),
+ kscale(s.f_bavail, s.f_bsize),
+ blocks_percent_used, mount_point);
#endif
}
+ }
- } while (1);
-
- bb_fflush_stdout_and_exit(status);
+ return status;
}
-
-/*
-Local Variables:
-c-file-style: "linux"
-c-basic-offset: 4
-tab-width: 4
-End:
-*/
diff --git a/release/src/router/busybox/coreutils/dirname.c b/release/src/router/busybox/coreutils/dirname.c
index d0c42b60..c0c0925e 100644
--- a/release/src/router/busybox/coreutils/dirname.c
+++ b/release/src/router/busybox/coreutils/dirname.c
@@ -2,32 +2,20 @@
/*
* Mini dirname implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/dirname.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int dirname_main(int argc, char **argv)
+int dirname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dirname_main(int argc, char **argv)
{
if (argc != 2) {
bb_show_usage();
@@ -35,5 +23,5 @@ extern int dirname_main(int argc, char **argv)
puts(dirname(argv[1]));
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ return fflush(stdout);
}
diff --git a/release/src/router/busybox/coreutils/dos2unix.c b/release/src/router/busybox/coreutils/dos2unix.c
index c28e6a8b..309cbc3b 100644
--- a/release/src/router/busybox/coreutils/dos2unix.c
+++ b/release/src/router/busybox/coreutils/dos2unix.c
@@ -1,196 +1,98 @@
+/* vi: set sw=4 ts=4: */
/*
* dos2unix for BusyBox
*
* dos2unix '\n' convertor 0.5.0
- * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
+ * based on Unix2Dos 0.9.0 by Peter Hanecak (made 19.2.1997)
* Copyright 1997,.. by Peter Hanecak <hanecak@megaloman.sk>.
* All rights reserved.
*
* dos2unix filters reading input from stdin and writing output to stdout.
- * Without arguments it reverts the format (e.i. if source is in UNIX format,
- * output is in DOS format and vice versa).
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * See the COPYING file for license information.
- */
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
-#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <fcntl.h>
-#include <sys/time.h>
-#include "busybox.h"
+#include "libbb.h"
-#define CT_AUTO 0
-#define CT_UNIX2DOS 1
-#define CT_DOS2UNIX 2
+enum {
+ CT_UNIX2DOS = 1,
+ CT_DOS2UNIX
+};
-/* We are making a lame pseudo-random string generator here. in
- * convert(), each pass through the while loop will add more and more
- * stuff into value, which is _supposed_ to wrap. We don't care about
- * it being accurate. We care about it being messy, since we then mod
- * it by the sizeof(letters) and then use that as an index into letters
- * to pick a random letter to add to out temporary file. */
-typedef unsigned long int bb_uint64_t;
-
-static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-// if fn is NULL then input is stdin and output is stdout
-static int convert(char *fn, int ConvType)
+/* if fn is NULL then input is stdin and output is stdout */
+static void convert(char *fn, int conv_type)
{
- int c, fd;
- struct timeval tv;
- char tempFn[BUFSIZ];
- static bb_uint64_t value=0;
- FILE *in = stdin, *out = stdout;
+ FILE *in, *out;
+ int i;
+ char *temp_fn = temp_fn; /* for compiler */
+ char *resolved_fn = resolved_fn;
+ in = stdin;
+ out = stdout;
if (fn != NULL) {
- in = bb_xfopen(fn, "rw");
- safe_strncpy(tempFn, fn, sizeof(tempFn));
- c = strlen(tempFn);
- tempFn[c] = '.';
- while(1) {
- if (c >=BUFSIZ)
- bb_error_msg_and_die("unique name not found");
- /* Get some semi random stuff to try and make a
- * random filename based (and in the same dir as)
- * the input file... */
- gettimeofday (&tv, NULL);
- value += ((bb_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
- tempFn[++c] = letters[value % 62];
- tempFn[c+1] = '\0';
- value /= 62;
-
- if ((fd = open(tempFn, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0 ) {
- continue;
- }
- out = fdopen(fd, "w+");
- if (!out) {
- close(fd);
- remove(tempFn);
- continue;
- }
- break;
+ struct stat st;
+
+ resolved_fn = xmalloc_follow_symlinks(fn);
+ if (resolved_fn == NULL)
+ bb_simple_perror_msg_and_die(fn);
+ in = xfopen_for_read(resolved_fn);
+ fstat(fileno(in), &st);
+
+ temp_fn = xasprintf("%sXXXXXX", resolved_fn);
+ i = mkstemp(temp_fn);
+ if (i == -1
+ || fchmod(i, st.st_mode) == -1
+ || !(out = fdopen(i, "w+"))
+ ) {
+ bb_simple_perror_msg_and_die(temp_fn);
}
}
- while ((c = fgetc(in)) != EOF) {
- if (c == '\r') {
- if ((ConvType == CT_UNIX2DOS) && (fn != NULL)) {
- // file is alredy in DOS format so it is not necessery to touch it
- remove(tempFn);
- if (fclose(in) < 0 || fclose(out) < 0) {
- bb_perror_nomsg();
- return -2;
- }
- return 0;
- }
- if (!ConvType)
- ConvType = CT_DOS2UNIX;
- break;
- }
- if (c == '\n') {
- if ((ConvType == CT_DOS2UNIX) && (fn != NULL)) {
- // file is alredy in UNIX format so it is not necessery to touch it
- remove(tempFn);
- if ((fclose(in) < 0) || (fclose(out) < 0)) {
- bb_perror_nomsg();
- return -2;
- }
- return 0;
- }
- if (!ConvType) {
- ConvType = CT_UNIX2DOS;
- }
- if (ConvType == CT_UNIX2DOS) {
+ while ((i = fgetc(in)) != EOF) {
+ if (i == '\r')
+ continue;
+ if (i == '\n')
+ if (conv_type == CT_UNIX2DOS)
fputc('\r', out);
- }
- fputc('\n', out);
- break;
- }
- fputc(c, out);
- }
- if (c != EOF)
- while ((c = fgetc(in)) != EOF) {
- if (c == '\r')
- continue;
- if (c == '\n') {
- if (ConvType == CT_UNIX2DOS)
- fputc('\r', out);
- fputc('\n', out);
- continue;
- }
- fputc(c, out);
+ fputc(i, out);
}
if (fn != NULL) {
- if (fclose(in) < 0 || fclose(out) < 0) {
- bb_perror_nomsg();
- remove(tempFn);
- return -2;
- }
-
- /* Assume they are both on the same filesystem (which
- * should be true since we put them into the same directory
- * so we _should_ be ok, but you never know... */
- if (rename(tempFn, fn) < 0) {
- bb_perror_msg("unable to rename '%s' as '%s'", tempFn, fn);
- return -1;
- }
+ if (fclose(in) < 0 || fclose(out) < 0) {
+ unlink(temp_fn);
+ bb_perror_nomsg_and_die();
+ }
+ xrename(temp_fn, resolved_fn);
+ free(temp_fn);
+ free(resolved_fn);
}
-
- return 0;
}
-int dos2unix_main(int argc, char *argv[])
+int dos2unix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int dos2unix_main(int argc, char **argv)
{
- int ConvType = CT_AUTO;
- int o;
+ int o, conv_type;
- //See if we are supposed to be doing dos2unix or unix2dos
- if (argv[0][0]=='d') {
- ConvType = CT_DOS2UNIX;
- }
- if (argv[0][0]=='u') {
- ConvType = CT_UNIX2DOS;
+ /* See if we are supposed to be doing dos2unix or unix2dos */
+ conv_type = CT_UNIX2DOS;
+ if (applet_name[0] == 'd') {
+ conv_type = CT_DOS2UNIX;
}
- // process parameters
- while ((o = getopt(argc, argv, "du")) != EOF) {
- switch (o) {
- case 'd':
- ConvType = CT_UNIX2DOS;
- break;
- case 'u':
- ConvType = CT_DOS2UNIX;
- break;
- default:
- bb_show_usage();
- }
- }
+ /* -u convert to unix, -d convert to dos */
+ opt_complementary = "u--d:d--u"; /* mutually exclusive */
+ o = getopt32(argv, "du");
- if (optind < argc) {
- while(optind < argc)
- if ((o = convert(argv[optind++], ConvType)) < 0)
- break;
- }
- else
- o = convert(NULL, ConvType);
+ /* Do the conversion requested by an argument else do the default
+ * conversion depending on our name. */
+ if (o)
+ conv_type = o;
- return o;
-}
+ do {
+ /* might be convert(NULL) if there is no filename given */
+ convert(argv[optind], conv_type);
+ optind++;
+ } while (optind < argc);
+ return 0;
+}
diff --git a/release/src/router/busybox/coreutils/du.c b/release/src/router/busybox/coreutils/du.c
index a9f6c28b..16c77324 100644
--- a/release/src/router/busybox/coreutils/du.c
+++ b/release/src/router/busybox/coreutils/du.c
@@ -6,20 +6,7 @@
* Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
* Copyright (C) 2002 Edward Betts <edward@debian.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */
@@ -36,67 +23,68 @@
* 4) Fixed busybox bug #1284 involving long overflow with human_readable.
*/
-#include <stdlib.h>
-#include <limits.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include "busybox.h"
-
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
-# ifdef CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K
-static unsigned long disp_hr = KILOBYTE;
-# else
-static unsigned long disp_hr = 512;
-# endif
-#elif defined CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K
-static unsigned int disp_k = 1;
+#include "libbb.h"
+
+enum {
+ OPT_a_files_too = (1 << 0),
+ OPT_H_follow_links = (1 << 1),
+ OPT_k_kbytes = (1 << 2),
+ OPT_L_follow_links = (1 << 3),
+ OPT_s_total_norecurse = (1 << 4),
+ OPT_x_one_FS = (1 << 5),
+ OPT_d_maxdepth = (1 << 6),
+ OPT_l_hardlinks = (1 << 7),
+ OPT_c_total = (1 << 8),
+ OPT_h_for_humans = (1 << 9),
+ OPT_m_mbytes = (1 << 10),
+};
+
+struct globals {
+#if ENABLE_FEATURE_HUMAN_READABLE
+ unsigned long disp_hr;
#else
-static unsigned int disp_k; /* bss inits to 0 */
-#endif
-
-static int max_print_depth = INT_MAX;
-static int count_hardlinks = INT_MAX;
-
-static int status
-#if EXIT_SUCCESS == 0
- = EXIT_SUCCESS
+ unsigned disp_k;
#endif
- ;
-static int print_files;
-static int slink_depth;
-static int du_depth;
-static int one_file_system;
-static dev_t dir_dev;
+ int max_print_depth;
+ bool status;
+ int slink_depth;
+ int du_depth;
+ dev_t dir_dev;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
-static void print(long size, char *filename)
+static void print(unsigned long size, const char *filename)
{
/* TODO - May not want to defer error checking here. */
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- bb_printf("%s\t%s\n", make_human_readable_str(size, 512, disp_hr),
- filename);
+#if ENABLE_FEATURE_HUMAN_READABLE
+ printf("%s\t%s\n", make_human_readable_str(size, 512, G.disp_hr),
+ filename);
#else
- bb_printf("%ld\t%s\n", size >> disp_k, filename);
+ if (G.disp_k) {
+ size++;
+ size >>= 1;
+ }
+ printf("%ld\t%s\n", size, filename);
#endif
}
/* tiny recursive du */
-static long du(char *filename)
+static unsigned long du(const char *filename)
{
struct stat statbuf;
- long sum;
+ unsigned long sum;
- if ((lstat(filename, &statbuf)) != 0) {
- bb_perror_msg("%s", filename);
- status = EXIT_FAILURE;
+ if (lstat(filename, &statbuf) != 0) {
+ bb_simple_perror_msg(filename);
+ G.status = EXIT_FAILURE;
return 0;
}
- if (one_file_system) {
- if (du_depth == 0) {
- dir_dev = statbuf.st_dev;
- } else if (dir_dev != statbuf.st_dev) {
+ if (option_mask32 & OPT_x_one_FS) {
+ if (G.du_depth == 0) {
+ G.dir_dev = statbuf.st_dev;
+ } else if (G.dir_dev != statbuf.st_dev) {
return 0;
}
}
@@ -104,22 +92,25 @@ static long du(char *filename)
sum = statbuf.st_blocks;
if (S_ISLNK(statbuf.st_mode)) {
- if (slink_depth > du_depth) { /* -H or -L */
- if ((stat(filename, &statbuf)) != 0) {
- bb_perror_msg("%s", filename);
- status = EXIT_FAILURE;
+ if (G.slink_depth > G.du_depth) { /* -H or -L */
+ if (stat(filename, &statbuf) != 0) {
+ bb_simple_perror_msg(filename);
+ G.status = EXIT_FAILURE;
return 0;
}
sum = statbuf.st_blocks;
- if (slink_depth == 1) {
- slink_depth = INT_MAX; /* Convert -H to -L. */
+ if (G.slink_depth == 1) {
+ /* Convert -H to -L */
+ G.slink_depth = INT_MAX;
}
}
}
- if (statbuf.st_nlink > count_hardlinks) {
+ if (!(option_mask32 & OPT_l_hardlinks)
+ && statbuf.st_nlink > 1
+ ) {
/* Add files/directories with links only once */
- if (is_in_ino_dev_hashtable(&statbuf, NULL)) {
+ if (is_in_ino_dev_hashtable(&statbuf)) {
return 0;
}
add_to_ino_dev_hashtable(&statbuf, NULL);
@@ -130,136 +121,108 @@ static long du(char *filename)
struct dirent *entry;
char *newfile;
- dir = opendir(filename);
+ dir = warn_opendir(filename);
if (!dir) {
- bb_perror_msg("%s", filename);
- status = EXIT_FAILURE;
+ G.status = EXIT_FAILURE;
return sum;
}
- newfile = last_char_is(filename, '/');
- if (newfile)
- *newfile = '\0';
-
while ((entry = readdir(dir))) {
- char *name = entry->d_name;
-
- newfile = concat_subpath_file(filename, name);
- if(newfile == NULL)
+ newfile = concat_subpath_file(filename, entry->d_name);
+ if (newfile == NULL)
continue;
- ++du_depth;
+ ++G.du_depth;
sum += du(newfile);
- --du_depth;
+ --G.du_depth;
free(newfile);
}
closedir(dir);
- } else if (du_depth > print_files) {
- return sum;
+ } else {
+ if (!(option_mask32 & OPT_a_files_too) && G.du_depth != 0)
+ return sum;
}
- if (du_depth <= max_print_depth) {
+ if (G.du_depth <= G.max_print_depth) {
print(sum, filename);
}
return sum;
}
-int du_main(int argc, char **argv)
+int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int du_main(int argc UNUSED_PARAM, char **argv)
{
- long total;
+ unsigned long total;
int slink_depth_save;
- int print_final_total;
- char *smax_print_depth;
- unsigned long opt;
+ unsigned opt;
-#ifdef CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K
- if (getenv("POSIXLY_CORRECT")) { /* TODO - a new libbb function? */
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- disp_hr = 512;
+#if ENABLE_FEATURE_HUMAN_READABLE
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
+ SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
+ if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */
+ G.disp_hr = 512;
#else
- disp_k = 0;
-#endif
- }
+ USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
+ /* SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */
#endif
+ G.max_print_depth = INT_MAX;
- /* Note: SUSv3 specifies that -a and -s options can not be used together
+ /* Note: SUSv3 specifies that -a and -s options cannot be used together
* in strictly conforming applications. However, it also says that some
* du implementations may produce output when -a and -s are used together.
* gnu du exits with an error code in this case. We choose to simply
* ignore -a. This is consistent with -s being equivalent to -d 0.
*/
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- bb_opt_complementaly = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s";
- opt = bb_getopt_ulflags(argc, argv, "aHkLsx" "d:" "lc" "hm", &smax_print_depth);
- if((opt & (1 << 9))) {
- /* -h opt */
- disp_hr = 0;
+#if ENABLE_FEATURE_HUMAN_READABLE
+ opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s:d+";
+ opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &G.max_print_depth);
+ argv += optind;
+ if (opt & OPT_h_for_humans) {
+ G.disp_hr = 0;
}
- if((opt & (1 << 10))) {
- /* -m opt */
- disp_hr = MEGABYTE;
+ if (opt & OPT_m_mbytes) {
+ G.disp_hr = 1024*1024;
}
- if((opt & (1 << 2))) {
- /* -k opt */
- disp_hr = KILOBYTE;
+ if (opt & OPT_k_kbytes) {
+ G.disp_hr = 1024;
}
#else
- bb_opt_complementaly = "H-L:L-H:s-d:d-s";
- opt = bb_getopt_ulflags(argc, argv, "aHkLsx" "d:" "lc", &smax_print_depth);
-#if !defined CONFIG_FEATURE_DU_DEFALT_BLOCKSIZE_1K
- if((opt & (1 << 2))) {
- /* -k opt */
- disp_k = 1;
+ opt_complementary = "H-L:L-H:s-d:d-s:d+";
+ opt = getopt32(argv, "aHkLsx" "d:" "lc", &G.max_print_depth);
+ argv += optind;
+#if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+ if (opt & OPT_k_kbytes) {
+ G.disp_k = 1;
}
#endif
#endif
- if((opt & (1 << 0))) {
- /* -a opt */
- print_files = INT_MAX;
- }
- if((opt & (1 << 1))) {
- /* -H opt */
- slink_depth = 1;
+ if (opt & OPT_H_follow_links) {
+ G.slink_depth = 1;
}
- if((opt & (1 << 3))) {
- /* -L opt */
- slink_depth = INT_MAX;
+ if (opt & OPT_L_follow_links) {
+ G.slink_depth = INT_MAX;
}
- if((opt & (1 << 4))) {
- /* -s opt */
- max_print_depth = 0;
- }
- one_file_system = opt & (1 << 5); /* -x opt */
- if((opt & (1 << 6))) {
- /* -d opt */
- max_print_depth = bb_xgetularg10_bnd(smax_print_depth, 0, INT_MAX);
- }
- if((opt & (1 << 7))) {
- /* -l opt */
- count_hardlinks = 1;
+ if (opt & OPT_s_total_norecurse) {
+ G.max_print_depth = 0;
}
- print_final_total = opt & (1 << 8); /* -c opt */
/* go through remaining args (if any) */
- argv += optind;
- if (optind >= argc) {
- *--argv = ".";
- if (slink_depth == 1) {
- slink_depth = 0;
+ if (!*argv) {
+ *--argv = (char*)".";
+ if (G.slink_depth == 1) {
+ G.slink_depth = 0;
}
}
- slink_depth_save = slink_depth;
+ slink_depth_save = G.slink_depth;
total = 0;
do {
total += du(*argv);
- slink_depth = slink_depth_save;
+ /* otherwise du /dir /dir won't show /dir twice: */
+ reset_ino_dev_hashtable();
+ G.slink_depth = slink_depth_save;
} while (*++argv);
-#ifdef CONFIG_FEATURE_CLEAN_UP
- reset_ino_dev_hashtable();
-#endif
- if (print_final_total) {
+ if (opt & OPT_c_total)
print(total, "total");
- }
- bb_fflush_stdout_and_exit(status);
+ fflush_stdout_and_exit(G.status);
}
diff --git a/release/src/router/busybox/coreutils/echo.c b/release/src/router/busybox/coreutils/echo.c
index b600a1fb..decca095 100644
--- a/release/src/router/busybox/coreutils/echo.c
+++ b/release/src/router/busybox/coreutils/echo.c
@@ -5,19 +5,7 @@
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
* Original copyright notice is retained at the end of this file.
*/
@@ -27,102 +15,133 @@
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
*
- * Because of behavioral differences, implemented configureable SUSv3
+ * Because of behavioral differences, implemented configurable SUSv3
* or 'fancy' gnu-ish behaviors. Also, reduced size and fixed bugs.
* 1) In handling '\c' escape, the previous version only suppressed the
* trailing newline. SUSv3 specifies _no_ output after '\c'.
* 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
- * The previous version version did not allow 4-digit octals.
+ * The previous version did not allow 4-digit octals.
*/
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int echo_main(int argc, char** argv)
+/* NB: can be used by shell even if not enabled as applet */
+
+int echo_main(int argc UNUSED_PARAM, char **argv)
{
-#ifndef CONFIG_FEATURE_FANCY_ECHO
-#define eflag '\\'
- ++argv;
+ const char *arg;
+#if !ENABLE_FEATURE_FANCY_ECHO
+ enum {
+ eflag = '\\',
+ nflag = 1, /* 1 -- print '\n' */
+ };
+
+ /* We must check that stdout is not closed.
+ * The reason for this is highly non-obvious.
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good. */
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+ if (fcntl(1, F_GETFL) == -1)
+ return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+ //if (dup2(1, 1) != 1) - old way
+ // return 1;
+
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
#else
const char *p;
- int nflag = 1;
- int eflag = 0;
+ char nflag = 1;
+ char eflag = 0;
+
+ /* We must check that stdout is not closed. */
+ if (fcntl(1, F_GETFL) == -1)
+ return 1;
+
+ while (1) {
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+ if (*arg != '-')
+ break;
- while (*++argv && (**argv == '-')) {
/* If it appears that we are handling options, then make sure
* that all of the options specified are actually valid.
* Otherwise, the string should just be echoed.
*/
-
- if (!*(p = *argv + 1)) { /* A single '-', so echo it. */
+ p = arg + 1;
+ if (!*p) /* A single '-', so echo it. */
goto just_echo;
- }
do {
- if (strrchr("neE", *p) == 0) {
+ if (!strrchr("neE", *p))
goto just_echo;
- }
} while (*++p);
/* All of the options in this arg are valid, so handle them. */
- p = *argv + 1;
+ p = arg + 1;
do {
- if (*p == 'n') {
+ if (*p == 'n')
nflag = 0;
- } else if (*p == 'e') {
+ if (*p == 'e')
eflag = '\\';
- } else {
- eflag = 0;
- }
} while (*++p);
}
-
-just_echo:
+ just_echo:
#endif
- while (*argv) {
- register int c;
+ while (1) {
+ /* arg is already == *argv and isn't NULL */
+ int c;
- while ((c = *(*argv)++)) {
+ if (!eflag) {
+ /* optimization for very common case */
+ fputs(arg, stdout);
+ } else while ((c = *arg++)) {
if (c == eflag) { /* Check for escape seq. */
- if (**argv == 'c') {
- /* '\c' means cancel newline and
+ if (*arg == 'c') {
+ /* '\c' means cancel newline and
* ignore all subsequent chars. */
- goto DONE;
+ goto ret;
}
-#ifndef CONFIG_FEATURE_FANCY_ECHO
+#if !ENABLE_FEATURE_FANCY_ECHO
/* SUSv3 specifies that octal escapes must begin with '0'. */
- if (((unsigned int)(**argv - '1')) >= 7)
+ if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */
#endif
{
/* Since SUSv3 mandates a first digit of 0, 4-digit octals
* of the form \0### are accepted. */
- if ((**argv == '0') && (((unsigned int)(argv[0][1] - '0')) < 8)) {
- (*argv)++;
+ if (*arg == '0') {
+ /* NB: don't turn "...\0" into "...\" */
+ if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) {
+ arg++;
+ }
}
- /* bb_process_escape_sequence can handle nul correctly */
- c = bb_process_escape_sequence((const char **) argv);
+ /* bb_process_escape_sequence handles NUL correctly
+ * ("...\" case). */
+ c = bb_process_escape_sequence(&arg);
}
}
- putchar(c);
+ bb_putchar(c);
}
- if (*++argv) {
- putchar(' ');
- }
+ arg = *++argv;
+ if (!arg)
+ break;
+ bb_putchar(' ');
}
-#ifdef CONFIG_FEATURE_FANCY_ECHO
+ newline_ret:
if (nflag) {
- putchar('\n');
+ bb_putchar('\n');
}
-#else
- putchar('\n');
-#endif
-
-DONE:
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ ret:
+ return fflush(stdout);
}
/*-
@@ -141,8 +160,8 @@ DONE:
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
+ * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
+ * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
*
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
@@ -163,3 +182,122 @@ DONE:
*
* @(#)echo.c 8.1 (Berkeley) 5/31/93
*/
+
+#ifdef VERSION_WITH_WRITEV
+/* We can't use stdio.
+ * The reason for this is highly non-obvious.
+ * echo_main is used from shell. Shell must correctly handle "echo foo"
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good.
+ *
+ * Using writev instead, with 'direct' conversion of argv vector.
+ */
+
+int echo_main(int argc, char **argv)
+{
+ struct iovec io[argc];
+ struct iovec *cur_io = io;
+ char *arg;
+ char *p;
+#if !ENABLE_FEATURE_FANCY_ECHO
+ enum {
+ eflag = '\\',
+ nflag = 1, /* 1 -- print '\n' */
+ };
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+#else
+ char nflag = 1;
+ char eflag = 0;
+
+ while (1) {
+ arg = *++argv;
+ if (!arg)
+ goto newline_ret;
+ if (*arg != '-')
+ break;
+
+ /* If it appears that we are handling options, then make sure
+ * that all of the options specified are actually valid.
+ * Otherwise, the string should just be echoed.
+ */
+ p = arg + 1;
+ if (!*p) /* A single '-', so echo it. */
+ goto just_echo;
+
+ do {
+ if (!strrchr("neE", *p))
+ goto just_echo;
+ } while (*++p);
+
+ /* All of the options in this arg are valid, so handle them. */
+ p = arg + 1;
+ do {
+ if (*p == 'n')
+ nflag = 0;
+ if (*p == 'e')
+ eflag = '\\';
+ } while (*++p);
+ }
+ just_echo:
+#endif
+
+ while (1) {
+ /* arg is already == *argv and isn't NULL */
+ int c;
+
+ cur_io->iov_base = p = arg;
+
+ if (!eflag) {
+ /* optimization for very common case */
+ p += strlen(arg);
+ } else while ((c = *arg++)) {
+ if (c == eflag) { /* Check for escape seq. */
+ if (*arg == 'c') {
+ /* '\c' means cancel newline and
+ * ignore all subsequent chars. */
+ cur_io->iov_len = p - (char*)cur_io->iov_base;
+ cur_io++;
+ goto ret;
+ }
+#if !ENABLE_FEATURE_FANCY_ECHO
+ /* SUSv3 specifies that octal escapes must begin with '0'. */
+ if ( (((unsigned char)*arg) - '1') >= 7)
+#endif
+ {
+ /* Since SUSv3 mandates a first digit of 0, 4-digit octals
+ * of the form \0### are accepted. */
+ if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
+ arg++;
+ }
+ /* bb_process_escape_sequence can handle nul correctly */
+ c = bb_process_escape_sequence( (void*) &arg);
+ }
+ }
+ *p++ = c;
+ }
+
+ arg = *++argv;
+ if (arg)
+ *p++ = ' ';
+ cur_io->iov_len = p - (char*)cur_io->iov_base;
+ cur_io++;
+ if (!arg)
+ break;
+ }
+
+ newline_ret:
+ if (nflag) {
+ cur_io->iov_base = (char*)"\n";
+ cur_io->iov_len = 1;
+ cur_io++;
+ }
+ ret:
+ /* TODO: implement and use full_writev? */
+ return writev(1, io, (cur_io - io)) >= 0;
+}
+#endif
diff --git a/release/src/router/busybox/coreutils/env.c b/release/src/router/busybox/coreutils/env.c
index d8a76e36..f50a03e8 100644
--- a/release/src/router/busybox/coreutils/env.c
+++ b/release/src/router/busybox/coreutils/env.c
@@ -5,19 +5,7 @@
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
* Original copyright notice is retained at the end of this file.
*
@@ -34,58 +22,55 @@
*/
/*
- * Modified by Vladimir Oleynik <andersen@codepoet.org> (C) 2003
- * - corretion "-" option usage
+ * Modified by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
+ * - correct "-" option usage
* - multiple "-u unsetenv" support
* - GNU long option support
- * - save errno after exec failed before bb_perror_msg()
+ * - use xfunc_error_retval
*/
+/* This is a NOEXEC applet. Be very careful! */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
-
+#include "libbb.h"
-static const struct option env_long_options[] = {
- { "ignore-environment", 0, NULL, 'i' },
- { "unset", 1, NULL, 'u' },
- { 0, 0, 0, 0 }
-};
+#if ENABLE_FEATURE_ENV_LONG_OPTIONS
+static const char env_longopts[] ALIGN1 =
+ "ignore-environment\0" No_argument "i"
+ "unset\0" Required_argument "u"
+ ;
+#endif
-extern int env_main(int argc, char** argv)
+int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int env_main(int argc UNUSED_PARAM, char **argv)
{
- char **ep, *p;
- char *cleanenv[1] = { NULL };
- unsigned long opt;
- llist_t *unset_env;
- extern char **environ;
-
- bb_opt_complementaly = "u*";
- bb_applet_long_options = env_long_options;
-
- opt = bb_getopt_ulflags(argc, argv, "+iu:", &unset_env);
-
+ char **ep;
+ unsigned opt;
+ llist_t *unset_env = NULL;
+
+ opt_complementary = "u::";
+#if ENABLE_FEATURE_ENV_LONG_OPTIONS
+ applet_long_options = env_longopts;
+#endif
+ opt = getopt32(argv, "+iu:", &unset_env);
argv += optind;
- if (*argv && (argv[0][0] == '-') && !argv[0][1]) {
+ if (*argv && LONE_DASH(argv[0])) {
opt |= 1;
++argv;
}
-
- if(opt & 1)
- environ = cleanenv;
- else if(opt & 2) {
- while(unset_env) {
- unsetenv(unset_env->data);
- unset_env = unset_env->link;
- }
+ if (opt & 1) {
+ clearenv();
+ }
+ while (unset_env) {
+ char *var = llist_pop(&unset_env);
+ /* This does not handle -uVAR=VAL
+ * (coreutils _sets_ the variable in that case): */
+ /*unsetenv(var);*/
+ /* This does, but uses somewhan undocumented feature that
+ * putenv("name_without_equal_sign") unsets the variable: */
+ putenv(var);
}
- while (*argv && ((p = strchr(*argv, '=')) != NULL)) {
+ while (*argv && (strchr(*argv, '=') != NULL)) {
if (putenv(*argv) < 0) {
bb_perror_msg_and_die("putenv");
}
@@ -93,19 +78,17 @@ extern int env_main(int argc, char** argv)
}
if (*argv) {
- int er;
-
- execvp(*argv, argv);
- er = errno;
- bb_perror_msg("%s", *argv); /* Avoid multibyte problems. */
- return (er == ENOENT) ? 127 : 126; /* SUSv3-mandated exit codes. */
+ BB_EXECVP(*argv, argv);
+ /* SUSv3-mandated exit codes. */
+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
+ bb_simple_perror_msg_and_die(*argv);
}
for (ep = environ; *ep; ep++) {
puts(*ep);
}
- bb_fflush_stdout_and_exit(0);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
}
/*
@@ -140,5 +123,3 @@ extern int env_main(int argc, char** argv)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
-
diff --git a/release/src/router/busybox/coreutils/expand.c b/release/src/router/busybox/coreutils/expand.c
new file mode 100644
index 00000000..0967e253
--- /dev/null
+++ b/release/src/router/busybox/coreutils/expand.c
@@ -0,0 +1,180 @@
+/* expand - convert tabs to spaces
+ * unexpand - convert spaces to tabs
+ *
+ * Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
+ * David MacKenzie <djm@gnu.ai.mit.edu>
+ *
+ * Options for expand:
+ * -t num --tabs=NUM Convert tabs to num spaces (default 8 spaces).
+ * -i --initial Only convert initial tabs on each line to spaces.
+ *
+ * Options for unexpand:
+ * -a --all Convert all blanks, instead of just initial blanks.
+ * -f --first-only Convert only leading sequences of blanks (default).
+ * -t num --tabs=NUM Have tabs num characters apart instead of 8.
+ *
+ * Busybox version (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Caveat: this versions of expand and unexpand don't accept tab lists.
+ */
+
+#include "libbb.h"
+
+enum {
+ OPT_INITIAL = 1 << 0,
+ OPT_TABS = 1 << 1,
+ OPT_ALL = 1 << 2,
+};
+
+#if ENABLE_EXPAND
+static void expand(FILE *file, int tab_size, unsigned opt)
+{
+ char *line;
+
+ tab_size = -tab_size;
+
+ while ((line = xmalloc_fgets(file)) != NULL) {
+ int pos;
+ unsigned char c;
+ char *ptr = line;
+
+ goto start;
+ while ((c = *ptr) != '\0') {
+ if ((opt & OPT_INITIAL) && !isblank(c)) {
+ fputs(ptr, stdout);
+ break;
+ }
+ ptr++;
+ if (c == '\t') {
+ c = ' ';
+ while (++pos < 0)
+ bb_putchar(c);
+ }
+ bb_putchar(c);
+ if (++pos >= 0) {
+ start:
+ pos = tab_size;
+ }
+ }
+ free(line);
+ }
+}
+#endif
+
+#if ENABLE_UNEXPAND
+static void unexpand(FILE *file, unsigned tab_size, unsigned opt)
+{
+ char *line;
+
+ while ((line = xmalloc_fgets(file)) != NULL) {
+ char *ptr = line;
+ unsigned column = 0;
+
+ while (*ptr) {
+ unsigned n;
+
+ while (*ptr == ' ') {
+ column++;
+ ptr++;
+ }
+ if (*ptr == '\t') {
+ column += tab_size - (column % tab_size);
+ ptr++;
+ continue;
+ }
+
+ n = column / tab_size;
+ column = column % tab_size;
+ while (n--)
+ putchar('\t');
+
+ if ((opt & OPT_INITIAL) && ptr != line) {
+ printf("%*s%s", column, "", ptr);
+ break;
+ }
+ n = strcspn(ptr, "\t ");
+ printf("%*s%.*s", column, "", n, ptr);
+ ptr += n;
+ column = (column + n) % tab_size;
+ }
+ free(line);
+ }
+}
+#endif
+
+int expand_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int expand_main(int argc UNUSED_PARAM, char **argv)
+{
+ /* Default 8 spaces for 1 tab */
+ const char *opt_t = "8";
+ FILE *file;
+ unsigned tab_size;
+ unsigned opt;
+ int exit_status = EXIT_SUCCESS;
+
+#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS
+ static const char expand_longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "initial\0" No_argument "i"
+ "tabs\0" Required_argument "t"
+ ;
+#endif
+#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS
+ static const char unexpand_longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "first-only\0" No_argument "i"
+ "tabs\0" Required_argument "t"
+ "all\0" No_argument "a"
+ ;
+#endif
+
+ if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
+ USE_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
+ opt = getopt32(argv, "it:", &opt_t);
+ } else {
+ USE_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
+ /* -t NUM sets also -a */
+ opt_complementary = "ta";
+ opt = getopt32(argv, "ft:a", &opt_t);
+ /* -f --first-only is the default */
+ if (!(opt & OPT_ALL)) opt |= OPT_INITIAL;
+ }
+ tab_size = xatou_range(opt_t, 1, UINT_MAX);
+
+ argv += optind;
+
+ if (!*argv) {
+ *--argv = (char*)bb_msg_standard_input;
+ }
+ do {
+ file = fopen_or_warn_stdin(*argv);
+ if (!file) {
+ exit_status = EXIT_FAILURE;
+ continue;
+ }
+
+ if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
+ USE_EXPAND(expand(file, tab_size, opt));
+ else
+ USE_UNEXPAND(unexpand(file, tab_size, opt));
+
+ /* Check and close the file */
+ if (fclose_if_not_stdin(file)) {
+ bb_simple_perror_msg(*argv);
+ exit_status = EXIT_FAILURE;
+ }
+ /* If stdin also clear EOF */
+ if (file == stdin)
+ clearerr(file);
+ } while (*++argv);
+
+ /* Now close stdin also */
+ /* (if we didn't read from it, it's a no-op) */
+ if (fclose(stdin))
+ bb_perror_msg_and_die(bb_msg_standard_input);
+
+ fflush_stdout_and_exit(exit_status);
+}
diff --git a/release/src/router/busybox/coreutils/expr.c b/release/src/router/busybox/coreutils/expr.c
index ecba825d..54c2ee16 100644
--- a/release/src/router/busybox/coreutils/expr.c
+++ b/release/src/router/busybox/coreutils/expr.c
@@ -5,27 +5,17 @@
* based on GNU expr Mike Parker.
* Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
*
- * Busybox modifications
+ * Busybox modifications
* Copyright (c) 2000 Edward Betts <edward@debian.org>.
+ * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
+ * - reduced 464 bytes.
+ * - 64 math support
*
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2 of the license, or
- * (at your option) any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the gnu
- * general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; if not, write to the free software
- * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* This program evaluates expressions. Each token (operator, operand,
- * parenthesis) of the expression must be a seperate argument. The
+ * parenthesis) of the expression must be a separate argument. The
* parser used is a reasonably general one, though any incarnation of
* it is language-specific. It is especially nice for expressions.
*
@@ -35,369 +25,339 @@
/* no getopt needed */
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <regex.h>
-#include <sys/types.h>
-#include "busybox.h"
+#include "libbb.h"
+#include "xregex.h"
+
+#if ENABLE_EXPR_MATH_SUPPORT_64
+typedef int64_t arith_t;
+#define PF_REZ "ll"
+#define PF_REZ_TYPE (long long)
+#define STRTOL(s, e, b) strtoll(s, e, b)
+#else
+typedef long arith_t;
+
+#define PF_REZ "l"
+#define PF_REZ_TYPE (long)
+#define STRTOL(s, e, b) strtol(s, e, b)
+#endif
+
+/* TODO: use bb_strtol[l]? It's easier to check for errors... */
/* The kinds of value we can have. */
-enum valtype {
- integer,
- string
+enum {
+ INTEGER,
+ STRING
};
-typedef enum valtype TYPE;
/* A value is.... */
struct valinfo {
- TYPE type; /* Which kind. */
- union { /* The value itself. */
- int i;
+ smallint type; /* Which kind. */
+ union { /* The value itself. */
+ arith_t i;
char *s;
} u;
};
typedef struct valinfo VALUE;
/* The arguments given to the program, minus the program name. */
-static char **args;
-
-static VALUE *docolon (VALUE *sv, VALUE *pv);
-static VALUE *eval (void);
-static VALUE *int_value (int i);
-static VALUE *str_value (char *s);
-static int nextarg (char *str);
-static int null (VALUE *v);
-static int toarith (VALUE *v);
-static void freev (VALUE *v);
-static void tostring (VALUE *v);
-
-int expr_main (int argc, char **argv)
-{
- VALUE *v;
-
- if (argc == 1) {
- bb_error_msg_and_die("too few arguments");
- }
-
- args = argv + 1;
-
- v = eval ();
- if (*args)
- bb_error_msg_and_die ("syntax error");
+struct globals {
+ char **args;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
- if (v->type == integer)
- printf ("%d\n", v->u.i);
- else
- puts (v->u.s);
+/* forward declarations */
+static VALUE *eval(void);
- exit (null (v));
-}
/* Return a VALUE for I. */
-static VALUE *int_value (int i)
+static VALUE *int_value(arith_t i)
{
VALUE *v;
- v = xmalloc (sizeof(VALUE));
- v->type = integer;
+ v = xzalloc(sizeof(VALUE));
+ if (INTEGER) /* otherwise xzaaloc did it already */
+ v->type = INTEGER;
v->u.i = i;
return v;
}
/* Return a VALUE for S. */
-static VALUE *str_value (char *s)
+static VALUE *str_value(const char *s)
{
VALUE *v;
- v = xmalloc (sizeof(VALUE));
- v->type = string;
- v->u.s = strdup (s);
+ v = xzalloc(sizeof(VALUE));
+ if (STRING) /* otherwise xzaaloc did it already */
+ v->type = STRING;
+ v->u.s = xstrdup(s);
return v;
}
/* Free VALUE V, including structure components. */
-static void freev (VALUE *v)
+static void freev(VALUE *v)
{
- if (v->type == string)
- free (v->u.s);
- free (v);
+ if (v->type == STRING)
+ free(v->u.s);
+ free(v);
}
/* Return nonzero if V is a null-string or zero-number. */
-static int null (VALUE *v)
+static int null(VALUE *v)
{
- switch (v->type) {
- case integer:
- return v->u.i == 0;
- case string:
- return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
- default:
- abort ();
- }
+ if (v->type == INTEGER)
+ return v->u.i == 0;
+ /* STRING: */
+ return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0');
}
-/* Coerce V to a string value (can't fail). */
+/* Coerce V to a STRING value (can't fail). */
-static void tostring (VALUE *v)
+static void tostring(VALUE *v)
{
- if (v->type == integer) {
- bb_xasprintf (&(v->u.s), "%d", v->u.i);
- v->type = string;
+ if (v->type == INTEGER) {
+ v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i);
+ v->type = STRING;
}
}
-/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
+/* Coerce V to an INTEGER value. Return 1 on success, 0 on failure. */
-static int toarith (VALUE *v)
+static bool toarith(VALUE *v)
{
- int i;
-
- switch (v->type) {
- case integer:
- return 1;
- case string:
- i = 0;
- /* Don't interpret the empty string as an integer. */
- if (v->u.s == 0)
- return 0;
- i = atoi(v->u.s);
- free (v->u.s);
- v->u.i = i;
- v->type = integer;
- return 1;
- default:
- abort ();
+ if (v->type == STRING) {
+ arith_t i;
+ char *e;
+
+ /* Don't interpret the empty string as an integer. */
+ /* Currently does not worry about overflow or int/long differences. */
+ i = STRTOL(v->u.s, &e, 10);
+ if ((v->u.s == e) || *e)
+ return 0;
+ free(v->u.s);
+ v->u.i = i;
+ v->type = INTEGER;
}
+ return 1;
}
-/* Return nonzero if the next token matches STR exactly.
+/* Return str[0]+str[1] if the next token matches STR exactly.
STR must not be NULL. */
-static int
-nextarg (char *str)
+static int nextarg(const char *str)
{
- if (*args == NULL)
+ if (*G.args == NULL || strcmp(*G.args, str) != 0)
return 0;
- return strcmp (*args, str) == 0;
+ return (unsigned char)str[0] + (unsigned char)str[1];
}
/* The comparison operator handling functions. */
-#define cmpf(name, rel) \
-static int name (VALUE *l, VALUE *r) \
-{ \
- if (l->type == string || r->type == string) { \
- tostring (l); \
- tostring (r); \
- return strcmp (l->u.s, r->u.s) rel 0; \
- } \
- else \
- return l->u.i rel r->u.i; \
+static int cmp_common(VALUE *l, VALUE *r, int op)
+{
+ arith_t ll, rr;
+
+ ll = l->u.i;
+ rr = r->u.i;
+ if (l->type == STRING || r->type == STRING) {
+ tostring(l);
+ tostring(r);
+ ll = strcmp(l->u.s, r->u.s);
+ rr = 0;
+ }
+ /* calculating ll - rr and checking the result is prone to overflows.
+ * We'll do it differently: */
+ if (op == '<')
+ return ll < rr;
+ if (op == ('<' + '='))
+ return ll <= rr;
+ if (op == '=' || (op == '=' + '='))
+ return ll == rr;
+ if (op == '!' + '=')
+ return ll != rr;
+ if (op == '>')
+ return ll > rr;
+ /* >= */
+ return ll >= rr;
}
- cmpf (less_than, <)
- cmpf (less_equal, <=)
- cmpf (equal, ==)
- cmpf (not_equal, !=)
- cmpf (greater_equal, >=)
- cmpf (greater_than, >)
-
-#undef cmpf
/* The arithmetic operator handling functions. */
-#define arithf(name, op) \
-static \
-int name (VALUE *l, VALUE *r) \
-{ \
- if (!toarith (l) || !toarith (r)) \
- bb_error_msg_and_die ("non-numeric argument"); \
- return l->u.i op r->u.i; \
-}
-
-#define arithdivf(name, op) \
-static int name (VALUE *l, VALUE *r) \
-{ \
- if (!toarith (l) || !toarith (r)) \
- bb_error_msg_and_die ( "non-numeric argument"); \
- if (r->u.i == 0) \
- bb_error_msg_and_die ( "division by zero"); \
- return l->u.i op r->u.i; \
+static arith_t arithmetic_common(VALUE *l, VALUE *r, int op)
+{
+ arith_t li, ri;
+
+ if (!toarith(l) || !toarith(r))
+ bb_error_msg_and_die("non-numeric argument");
+ li = l->u.i;
+ ri = r->u.i;
+ if (op == '+')
+ return li + ri;
+ if (op == '-')
+ return li - ri;
+ if (op == '*')
+ return li * ri;
+ if (ri == 0)
+ bb_error_msg_and_die("division by zero");
+ if (op == '/')
+ return li / ri;
+ return li % ri;
}
- arithf (plus, +)
- arithf (minus, -)
- arithf (multiply, *)
- arithdivf (divide, /)
- arithdivf (mod, %)
-
-#undef arithf
-#undef arithdivf
-
/* Do the : operator.
SV is the VALUE for the lhs (the string),
PV is the VALUE for the rhs (the pattern). */
-static VALUE *docolon (VALUE *sv, VALUE *pv)
+static VALUE *docolon(VALUE *sv, VALUE *pv)
{
VALUE *v;
- const char *errmsg;
- struct re_pattern_buffer re_buffer;
- struct re_registers re_regs;
- int len;
+ regex_t re_buffer;
+ const int NMATCH = 2;
+ regmatch_t re_regs[NMATCH];
- tostring (sv);
- tostring (pv);
+ tostring(sv);
+ tostring(pv);
if (pv->u.s[0] == '^') {
- fprintf (stderr, "\
-warning: unportable BRE: `%s': using `^' as the first character\n\
-of a basic regular expression is not portable; it is being ignored",
- pv->u.s);
+ bb_error_msg(
+"warning: '%s': using '^' as the first character\n"
+"of a basic regular expression is not portable; it is ignored", pv->u.s);
}
- len = strlen (pv->u.s);
- memset (&re_buffer, 0, sizeof (re_buffer));
- memset (&re_regs, 0, sizeof (re_regs));
- re_buffer.allocated = 2 * len;
- re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
- re_buffer.translate = 0;
- re_syntax_options = RE_SYNTAX_POSIX_BASIC;
- errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
- if (errmsg) {
- bb_error_msg_and_die("%s", errmsg);
- }
+ memset(&re_buffer, 0, sizeof(re_buffer));
+ memset(re_regs, 0, sizeof(re_regs));
+ xregcomp(&re_buffer, pv->u.s, 0);
- len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
- if (len >= 0) {
+ /* expr uses an anchored pattern match, so check that there was a
+ * match and that the match starts at offset 0. */
+ if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH
+ && re_regs[0].rm_so == 0
+ ) {
/* Were \(...\) used? */
- if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
- sv->u.s[re_regs.end[1]] = '\0';
- v = str_value (sv->u.s + re_regs.start[1]);
+ if (re_buffer.re_nsub > 0 && re_regs[1].rm_so >= 0) {
+ sv->u.s[re_regs[1].rm_eo] = '\0';
+ v = str_value(sv->u.s + re_regs[1].rm_so);
+ } else {
+ v = int_value(re_regs[0].rm_eo);
}
- else
- v = int_value (len);
- }
- else {
+ } else {
/* Match failed -- return the right kind of null. */
if (re_buffer.re_nsub > 0)
- v = str_value ("");
+ v = str_value("");
else
- v = int_value (0);
+ v = int_value(0);
}
- free (re_buffer.buffer);
+ regfree(&re_buffer);
return v;
}
/* Handle bare operands and ( expr ) syntax. */
-static VALUE *eval7 (void)
+static VALUE *eval7(void)
{
VALUE *v;
- if (!*args)
- bb_error_msg_and_die ( "syntax error");
+ if (!*G.args)
+ bb_error_msg_and_die("syntax error");
- if (nextarg ("(")) {
- args++;
- v = eval ();
- if (!nextarg (")"))
- bb_error_msg_and_die ( "syntax error");
- args++;
- return v;
- }
+ if (nextarg("(")) {
+ G.args++;
+ v = eval();
+ if (!nextarg(")"))
+ bb_error_msg_and_die("syntax error");
+ G.args++;
+ return v;
+ }
- if (nextarg (")"))
- bb_error_msg_and_die ( "syntax error");
+ if (nextarg(")"))
+ bb_error_msg_and_die("syntax error");
- return str_value (*args++);
+ return str_value(*G.args++);
}
/* Handle match, substr, index, length, and quote keywords. */
-static VALUE *eval6 (void)
+static VALUE *eval6(void)
{
- VALUE *l, *r, *v, *i1, *i2;
-
- if (nextarg ("quote")) {
- args++;
- if (!*args)
- bb_error_msg_and_die ( "syntax error");
- return str_value (*args++);
+ static const char keywords[] ALIGN1 =
+ "quote\0""length\0""match\0""index\0""substr\0";
+
+ VALUE *r, *i1, *i2;
+ VALUE *l = l; /* silence gcc */
+ VALUE *v = v; /* silence gcc */
+ int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0;
+
+ if (key == 0) /* not a keyword */
+ return eval7();
+ G.args++; /* We have a valid token, so get the next argument. */
+ if (key == 1) { /* quote */
+ if (!*G.args)
+ bb_error_msg_and_die("syntax error");
+ return str_value(*G.args++);
}
- else if (nextarg ("length")) {
- args++;
- r = eval6 ();
- tostring (r);
- v = int_value (strlen (r->u.s));
- freev (r);
- return v;
- }
- else if (nextarg ("match")) {
- args++;
- l = eval6 ();
- r = eval6 ();
- v = docolon (l, r);
- freev (l);
- freev (r);
- return v;
+ if (key == 2) { /* length */
+ r = eval6();
+ tostring(r);
+ v = int_value(strlen(r->u.s));
+ freev(r);
+ } else
+ l = eval6();
+
+ if (key == 3) { /* match */
+ r = eval6();
+ v = docolon(l, r);
+ freev(l);
+ freev(r);
}
- else if (nextarg ("index")) {
- args++;
- l = eval6 ();
- r = eval6 ();
- tostring (l);
- tostring (r);
- v = int_value (strcspn (l->u.s, r->u.s) + 1);
- if (v->u.i == (int) strlen (l->u.s) + 1)
+ if (key == 4) { /* index */
+ r = eval6();
+ tostring(l);
+ tostring(r);
+ v = int_value(strcspn(l->u.s, r->u.s) + 1);
+ if (v->u.i == (arith_t) strlen(l->u.s) + 1)
v->u.i = 0;
- freev (l);
- freev (r);
- return v;
+ freev(l);
+ freev(r);
}
- else if (nextarg ("substr")) {
- args++;
- l = eval6 ();
- i1 = eval6 ();
- i2 = eval6 ();
- tostring (l);
- if (!toarith (i1) || !toarith (i2)
- || i1->u.i > (int) strlen (l->u.s)
- || i1->u.i <= 0 || i2->u.i <= 0)
- v = str_value ("");
+ if (key == 5) { /* substr */
+ i1 = eval6();
+ i2 = eval6();
+ tostring(l);
+ if (!toarith(i1) || !toarith(i2)
+ || i1->u.i > (arith_t) strlen(l->u.s)
+ || i1->u.i <= 0 || i2->u.i <= 0)
+ v = str_value("");
else {
- v = xmalloc (sizeof(VALUE));
- v->type = string;
- v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
+ v = xmalloc(sizeof(VALUE));
+ v->type = STRING;
+ v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
}
- freev (l);
- freev (i1);
- freev (i2);
- return v;
+ freev(l);
+ freev(i1);
+ freev(i2);
}
- else
- return eval7 ();
+ return v;
+
}
/* Handle : operator (pattern matching).
Calls docolon to do the real work. */
-static VALUE *eval5 (void)
+static VALUE *eval5(void)
{
VALUE *l, *r, *v;
- l = eval6 ();
- while (nextarg (":")) {
- args++;
- r = eval6 ();
- v = docolon (l, r);
- freev (l);
- freev (r);
+ l = eval6();
+ while (nextarg(":")) {
+ G.args++;
+ r = eval6();
+ v = docolon(l, r);
+ freev(l);
+ freev(r);
l = v;
}
return l;
@@ -405,125 +365,137 @@ static VALUE *eval5 (void)
/* Handle *, /, % operators. */
-static VALUE *eval4 (void)
+static VALUE *eval4(void)
{
VALUE *l, *r;
- int (*fxn) (VALUE *, VALUE *), val;
+ int op;
+ arith_t val;
- l = eval5 ();
+ l = eval5();
while (1) {
- if (nextarg ("*"))
- fxn = multiply;
- else if (nextarg ("/"))
- fxn = divide;
- else if (nextarg ("%"))
- fxn = mod;
- else
- return l;
- args++;
- r = eval5 ();
- val = (*fxn) (l, r);
- freev (l);
- freev (r);
- l = int_value (val);
+ op = nextarg("*");
+ if (!op) { op = nextarg("/");
+ if (!op) { op = nextarg("%");
+ if (!op) return l;
+ }}
+ G.args++;
+ r = eval5();
+ val = arithmetic_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
}
}
/* Handle +, - operators. */
-static VALUE *eval3 (void)
+static VALUE *eval3(void)
{
VALUE *l, *r;
- int (*fxn) (VALUE *, VALUE *), val;
+ int op;
+ arith_t val;
- l = eval4 ();
+ l = eval4();
while (1) {
- if (nextarg ("+"))
- fxn = plus;
- else if (nextarg ("-"))
- fxn = minus;
- else
- return l;
- args++;
- r = eval4 ();
- val = (*fxn) (l, r);
- freev (l);
- freev (r);
- l = int_value (val);
+ op = nextarg("+");
+ if (!op) {
+ op = nextarg("-");
+ if (!op) return l;
+ }
+ G.args++;
+ r = eval4();
+ val = arithmetic_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
}
}
/* Handle comparisons. */
-static VALUE *eval2 (void)
+static VALUE *eval2(void)
{
VALUE *l, *r;
- int (*fxn) (VALUE *, VALUE *), val;
+ int op;
+ arith_t val;
- l = eval3 ();
+ l = eval3();
while (1) {
- if (nextarg ("<"))
- fxn = less_than;
- else if (nextarg ("<="))
- fxn = less_equal;
- else if (nextarg ("=") || nextarg ("=="))
- fxn = equal;
- else if (nextarg ("!="))
- fxn = not_equal;
- else if (nextarg (">="))
- fxn = greater_equal;
- else if (nextarg (">"))
- fxn = greater_than;
- else
- return l;
- args++;
- r = eval3 ();
- toarith (l);
- toarith (r);
- val = (*fxn) (l, r);
- freev (l);
- freev (r);
- l = int_value (val);
+ op = nextarg("<");
+ if (!op) { op = nextarg("<=");
+ if (!op) { op = nextarg("=");
+ if (!op) { op = nextarg("==");
+ if (!op) { op = nextarg("!=");
+ if (!op) { op = nextarg(">=");
+ if (!op) { op = nextarg(">");
+ if (!op) return l;
+ }}}}}}
+ G.args++;
+ r = eval3();
+ toarith(l);
+ toarith(r);
+ val = cmp_common(l, r, op);
+ freev(l);
+ freev(r);
+ l = int_value(val);
}
}
/* Handle &. */
-static VALUE *eval1 (void)
+static VALUE *eval1(void)
{
VALUE *l, *r;
- l = eval2 ();
- while (nextarg ("&")) {
- args++;
- r = eval2 ();
- if (null (l) || null (r)) {
- freev (l);
- freev (r);
- l = int_value (0);
- }
- else
- freev (r);
+ l = eval2();
+ while (nextarg("&")) {
+ G.args++;
+ r = eval2();
+ if (null(l) || null(r)) {
+ freev(l);
+ freev(r);
+ l = int_value(0);
+ } else
+ freev(r);
}
return l;
}
/* Handle |. */
-static VALUE *eval (void)
+static VALUE *eval(void)
{
VALUE *l, *r;
- l = eval1 ();
- while (nextarg ("|")) {
- args++;
- r = eval1 ();
- if (null (l)) {
- freev (l);
+ l = eval1();
+ while (nextarg("|")) {
+ G.args++;
+ r = eval1();
+ if (null(l)) {
+ freev(l);
l = r;
- }
- else
- freev (r);
+ } else
+ freev(r);
}
return l;
}
+
+int expr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int expr_main(int argc UNUSED_PARAM, char **argv)
+{
+ VALUE *v;
+
+ xfunc_error_retval = 2; /* coreutils compat */
+ G.args = argv + 1;
+ if (*G.args == NULL) {
+ bb_error_msg_and_die("too few arguments");
+ }
+ v = eval();
+ if (*G.args)
+ bb_error_msg_and_die("syntax error");
+ if (v->type == INTEGER)
+ printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
+ else
+ puts(v->u.s);
+ fflush_stdout_and_exit(null(v));
+}
diff --git a/release/src/router/busybox/coreutils/false.c b/release/src/router/busybox/coreutils/false.c
index a07b99d9..f448ebf7 100644
--- a/release/src/router/busybox/coreutils/false.c
+++ b/release/src/router/busybox/coreutils/false.c
@@ -2,31 +2,20 @@
/*
* Mini false implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
-/* http://www.opengroup.org/onlinepubs/007904975/utilities/false.html */
+/* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */
+
+#include "libbb.h"
-#include <stdlib.h>
-#include "busybox.h"
+/* This is a NOFORK applet. Be very careful! */
-extern int false_main(int argc, char **argv)
+int false_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int false_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
return EXIT_FAILURE;
}
diff --git a/release/src/router/busybox/coreutils/fold.c b/release/src/router/busybox/coreutils/fold.c
index df511075..e2a30d5d 100644
--- a/release/src/router/busybox/coreutils/fold.c
+++ b/release/src/router/busybox/coreutils/fold.c
@@ -1,46 +1,28 @@
+/* vi: set sw=4 ts=4: */
/* fold -- wrap each input line to fit in specified width.
Written by David MacKenzie, djm@gnu.ai.mit.edu.
Copyright (C) 91, 1995-2002 Free Software Foundation, Inc.
Modified for busybox based on coreutils v 5.0
- Copyright (C) 2003 Glenn McGrath <bug1@optushome.com.au>
+ Copyright (C) 2003 Glenn McGrath
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/types.h>
-
-#include "busybox.h"
+#include "libbb.h"
-/* If nonzero, count bytes, not column positions. */
-static int count_bytes;
+/* Must match getopt32 call */
+#define FLAG_COUNT_BYTES 1
+#define FLAG_BREAK_SPACES 2
+#define FLAG_WIDTH 4
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
-
static int adjust_column(int column, char c)
{
- if (!count_bytes) {
+ if (!(option_mask32 & FLAG_COUNT_BYTES)) {
if (c == '\b') {
if (column > 0)
column--;
@@ -55,140 +37,115 @@ static int adjust_column(int column, char c)
return column;
}
-extern int fold_main(int argc, char **argv)
+int fold_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fold_main(int argc, char **argv)
{
- /* If nonzero, try to break on whitespace. */
- int break_spaces;
-
- /* If nonzero, at least one of the files we read was standard input. */
- int have_read_stdin;
-
+ char *line_out = NULL;
+ int allocated_out = 0;
+ char *w_opt;
int width = 80;
int i;
- int optc;
int errs = 0;
- break_spaces = count_bytes = have_read_stdin = 0;
-
- /* Turn any numeric options into -w options. */
- for (i = 1; i < argc; i++) {
- char const *a = argv[i];
+ if (ENABLE_INCLUDE_SUSv2) {
+ /* Turn any numeric options into -w options. */
+ for (i = 1; i < argc; i++) {
+ char const *a = argv[i];
- if (a[0] == '-') {
- if (a[1] == '-' && !a[2])
- break;
- if (isdigit(a[1])) {
- char *s = xmalloc(strlen(a) + 2);
-
- s[0] = '-';
- s[1] = 'w';
- strcpy(s + 2, a + 1);
- argv[i] = s;
+ if (*a++ == '-') {
+ if (*a == '-' && !a[1]) /* "--" */
+ break;
+ if (isdigit(*a))
+ argv[i] = xasprintf("-w%s", a);
}
}
}
- while ((optc = getopt(argc, argv, "bsw:")) > 0) {
- switch (optc) {
- case 'b': /* Count bytes rather than columns. */
- count_bytes = 1;
- break;
- case 's': /* Break at word boundaries. */
- break_spaces = 1;
- break;
- case 'w': { /* Line width. */
- width = bb_xgetlarg(optarg, 10, 1, 10000);
- break;
- }
- default:
- bb_show_usage();
- }
- }
+ getopt32(argv, "bsw:", &w_opt);
+ if (option_mask32 & FLAG_WIDTH)
+ width = xatoul_range(w_opt, 1, 10000);
argv += optind;
- if (!*argv) {
- *--argv = "-";
- }
+ if (!*argv)
+ *--argv = (char*)"-";
do {
- FILE *istream = bb_wfopen_input(*argv);
- if (istream != NULL) {
- int c;
- int column = 0; /* Screen column where next char will go. */
- int offset_out = 0; /* Index in `line_out' for next char. */
- static char *line_out = NULL;
- static int allocated_out = 0;
-
- while ((c = getc(istream)) != EOF) {
- if (offset_out + 1 >= allocated_out) {
- allocated_out += 1024;
- line_out = xrealloc(line_out, allocated_out);
- }
+ FILE *istream = fopen_or_warn_stdin(*argv);
+ int c;
+ int column = 0; /* Screen column where next char will go. */
+ int offset_out = 0; /* Index in 'line_out' for next char. */
- if (c == '\n') {
- line_out[offset_out++] = c;
- fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
- column = offset_out = 0;
- continue;
- }
+ if (istream == NULL) {
+ errs |= EXIT_FAILURE;
+ continue;
+ }
-rescan:
- column = adjust_column(column, c);
-
- if (column > width) {
- /* This character would make the line too long.
- Print the line plus a newline, and make this character
- start the next line. */
- if (break_spaces) {
- /* Look for the last blank. */
- int logical_end;
-
- for (logical_end = offset_out - 1; logical_end >= 0; logical_end--) {
- if (isblank(line_out[logical_end])) {
- break;
- }
- }
- if (logical_end >= 0) {
- /* Found a blank. Don't output the part after it. */
- logical_end++;
- fwrite(line_out, sizeof(char), (size_t) logical_end, stdout);
- putchar('\n');
- /* Move the remainder to the beginning of the next line.
- The areas being copied here might overlap. */
- memmove(line_out, line_out + logical_end, offset_out - logical_end);
- offset_out -= logical_end;
- for (column = i = 0; i < offset_out; i++) {
- column = adjust_column(column, line_out[i]);
- }
- goto rescan;
+ while ((c = getc(istream)) != EOF) {
+ if (offset_out + 1 >= allocated_out) {
+ allocated_out += 1024;
+ line_out = xrealloc(line_out, allocated_out);
+ }
+
+ if (c == '\n') {
+ line_out[offset_out++] = c;
+ fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ column = offset_out = 0;
+ continue;
+ }
+ rescan:
+ column = adjust_column(column, c);
+
+ if (column > width) {
+ /* This character would make the line too long.
+ Print the line plus a newline, and make this character
+ start the next line. */
+ if (option_mask32 & FLAG_BREAK_SPACES) {
+ /* Look for the last blank. */
+ int logical_end;
+
+ for (logical_end = offset_out - 1; logical_end >= 0; logical_end--) {
+ if (isblank(line_out[logical_end])) {
+ break;
}
- } else {
- if (offset_out == 0) {
- line_out[offset_out++] = c;
- continue;
+ }
+ if (logical_end >= 0) {
+ /* Found a blank. Don't output the part after it. */
+ logical_end++;
+ fwrite(line_out, sizeof(char), (size_t) logical_end, stdout);
+ bb_putchar('\n');
+ /* Move the remainder to the beginning of the next line.
+ The areas being copied here might overlap. */
+ memmove(line_out, line_out + logical_end, offset_out - logical_end);
+ offset_out -= logical_end;
+ for (column = i = 0; i < offset_out; i++) {
+ column = adjust_column(column, line_out[i]);
}
+ goto rescan;
+ }
+ } else {
+ if (offset_out == 0) {
+ line_out[offset_out++] = c;
+ continue;
}
- line_out[offset_out++] = '\n';
- fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
- column = offset_out = 0;
- goto rescan;
}
-
- line_out[offset_out++] = c;
- }
-
- if (offset_out) {
+ line_out[offset_out++] = '\n';
fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ column = offset_out = 0;
+ goto rescan;
}
- if (ferror(istream) || bb_fclose_nonstdin(istream)) {
- bb_perror_msg("%s", *argv); /* Avoid multibyte problems. */
- errs |= EXIT_FAILURE;
- }
- } else {
+ line_out[offset_out++] = c;
+ }
+
+ if (offset_out) {
+ fwrite(line_out, sizeof(char), (size_t) offset_out, stdout);
+ }
+
+ if (fclose_if_not_stdin(istream)) {
+ bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */
errs |= EXIT_FAILURE;
}
} while (*++argv);
- bb_fflush_stdout_and_exit(errs);
+ fflush_stdout_and_exit(errs);
}
diff --git a/release/src/router/busybox/coreutils/head.c b/release/src/router/busybox/coreutils/head.c
index dab4de11..ac476d09 100644
--- a/release/src/router/busybox/coreutils/head.c
+++ b/release/src/router/busybox/coreutils/head.c
@@ -4,51 +4,42 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <ctype.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-static const char head_opts[] =
+static const char head_opts[] ALIGN1 =
"n:"
-#ifdef CONFIG_FEATURE_FANCY_HEAD
+#if ENABLE_FEATURE_FANCY_HEAD
"c:qv"
#endif
;
-static const char header_fmt_str[] = "\n==> %s <==\n";
+#if ENABLE_FEATURE_FANCY_HEAD
+static const struct suffix_mult head_suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
+};
+#endif
+
+static const char header_fmt_str[] ALIGN1 = "\n==> %s <==\n";
+int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int head_main(int argc, char **argv)
{
unsigned long count = 10;
unsigned long i;
-#ifdef CONFIG_FEATURE_FANCY_HEAD
+#if ENABLE_FEATURE_FANCY_HEAD
int count_bytes = 0;
int header_threshhold = 1;
#endif
-
FILE *fp;
const char *fmt;
char *p;
@@ -56,53 +47,61 @@ int head_main(int argc, char **argv)
int c;
int retval = EXIT_SUCCESS;
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
/* Allow legacy syntax of an initial numeric option without -n. */
- if ((argc > 1) && (argv[1][0] == '-')
- /* && (isdigit)(argv[1][1]) */
- && (((unsigned int)(argv[1][1] - '0')) <= 9)
+ if (argv[1] && argv[1][0] == '-'
+ && isdigit(argv[1][1])
) {
--argc;
++argv;
p = (*argv) + 1;
goto GET_COUNT;
}
+#endif
+ /* No size benefit in converting this to getopt32 */
while ((opt = getopt(argc, argv, head_opts)) > 0) {
- switch(opt) {
-#ifdef CONFIG_FEATURE_FANCY_HEAD
- case 'q':
- header_threshhold = INT_MAX;
- break;
- case 'v':
- header_threshhold = -1;
- break;
- case 'c':
- count_bytes = 1;
- /* fall through */
+ switch (opt) {
+#if ENABLE_FEATURE_FANCY_HEAD
+ case 'q':
+ header_threshhold = INT_MAX;
+ break;
+ case 'v':
+ header_threshhold = -1;
+ break;
+ case 'c':
+ count_bytes = 1;
+ /* fall through */
+#endif
+ case 'n':
+ p = optarg;
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
+ GET_COUNT:
#endif
- case 'n':
- p = optarg;
- GET_COUNT:
- count = bb_xgetularg10(p);
- break;
- default:
- bb_show_usage();
+#if !ENABLE_FEATURE_FANCY_HEAD
+ count = xatoul(p);
+#else
+ count = xatoul_sfx(p, head_suffixes);
+#endif
+ break;
+ default:
+ bb_show_usage();
}
}
+ argc -= optind;
argv += optind;
- if (!*argv) {
- *--argv = "-";
- }
+ if (!*argv)
+ *--argv = (char*)"-";
fmt = header_fmt_str + 1;
-#ifdef CONFIG_FEATURE_FANCY_HEAD
- if (argc - optind <= header_threshhold) {
+#if ENABLE_FEATURE_FANCY_HEAD
+ if (argc <= header_threshhold) {
header_threshhold = 0;
}
#else
- if (argc <= optind + 1) {
- fmt += 11;
+ if (argc <= 1) {
+ fmt += 11; /* "" */
}
/* Now define some things here to avoid #ifdefs in the code below.
* These should optimize out of the if conditions below. */
@@ -111,12 +110,13 @@ int head_main(int argc, char **argv)
#endif
do {
- if ((fp = bb_wfopen_input(*argv)) != NULL) {
+ fp = fopen_or_warn_stdin(*argv);
+ if (fp) {
if (fp == stdin) {
*argv = (char *) bb_msg_standard_input;
}
if (header_threshhold) {
- bb_printf(fmt, *argv);
+ printf(fmt, *argv);
}
i = count;
while (i && ((c = getc(fp)) != EOF)) {
@@ -125,14 +125,16 @@ int head_main(int argc, char **argv)
}
putchar(c);
}
- if (bb_fclose_nonstdin(fp)) {
- bb_perror_msg("%s", *argv); /* Avoid multibyte problems. */
+ if (fclose_if_not_stdin(fp)) {
+ bb_simple_perror_msg(*argv);
retval = EXIT_FAILURE;
}
- bb_xferror_stdout();
+ die_if_ferror_stdout();
+ } else {
+ retval = EXIT_FAILURE;
}
fmt = header_fmt_str;
} while (*++argv);
- bb_fflush_stdout_and_exit(retval);
+ fflush_stdout_and_exit(retval);
}
diff --git a/release/src/router/busybox/coreutils/hostid.c b/release/src/router/busybox/coreutils/hostid.c
index 917dc223..2794510a 100644
--- a/release/src/router/busybox/coreutils/hostid.c
+++ b/release/src/router/busybox/coreutils/hostid.c
@@ -4,35 +4,23 @@
*
* Copyright (C) 2000 Edward Betts <edward@debian.org>.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int hostid_main(int argc, char **argv)
+int hostid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int hostid_main(int argc, char **argv UNUSED_PARAM)
{
if (argc > 1) {
bb_show_usage();
}
- bb_printf("%lx\n", gethostid());
+ printf("%lx\n", gethostid());
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ return fflush(stdout);
}
diff --git a/release/src/router/busybox/coreutils/id.c b/release/src/router/busybox/coreutils/id.c
index 971e7cda..43f403fa 100644
--- a/release/src/router/busybox/coreutils/id.c
+++ b/release/src/router/busybox/coreutils/id.c
@@ -3,108 +3,212 @@
* Mini id implementation for busybox
*
* Copyright (C) 2000 by Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2008 by Tito Ragusa <farmatito@tiscali.it>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/* BB_AUDIT SUSv3 _NOT_ compliant -- option -G is not currently supported. */
+/* BB_AUDIT SUSv3 compliant. */
+/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever
+ * length and to be more similar to GNU id.
+ * -Z option support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ * Added -G option Tito Ragusa (C) 2008 for SUSv3.
+ */
-#include "busybox.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <string.h>
-#include <sys/types.h>
-#ifdef CONFIG_SELINUX
-#include <proc_secure.h>
-#include <flask_util.h>
-#endif
+#include "libbb.h"
-#define JUST_USER 1
-#define JUST_GROUP 2
-#define PRINT_REAL 4
-#define NAME_NOT_NUMBER 8
+#if !ENABLE_USE_BB_PWD_GRP
+#if defined(__UCLIBC_MAJOR__) && (__UCLIBC_MAJOR__ == 0)
+#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30)
+#error "Sorry, you need at least uClibc version 0.9.30 for id applet to build"
+#endif
+#endif
+#endif
-extern int id_main(int argc, char **argv)
-{
- char user[9], group[9];
- long pwnam, grnam;
- int uid, gid;
- int flags;
-#ifdef CONFIG_SELINUX
- int is_flask_enabled_flag = is_flask_enabled();
+enum {
+ PRINT_REAL = (1 << 0),
+ NAME_NOT_NUMBER = (1 << 1),
+ JUST_USER = (1 << 2),
+ JUST_GROUP = (1 << 3),
+ JUST_ALL_GROUPS = (1 << 4),
+#if ENABLE_SELINUX
+ JUST_CONTEXT = (1 << 5),
#endif
-
- flags = bb_getopt_ulflags(argc, argv, "ugrn");
+};
- if (((flags & (JUST_USER | JUST_GROUP)) == (JUST_USER | JUST_GROUP))
- || (argc > optind + 1)
- ) {
- bb_show_usage();
+static int print_common(unsigned id, const char *name, const char *prefix)
+{
+ if (prefix) {
+ printf("%s", prefix);
}
-
- if (argv[optind] == NULL) {
- if (flags & PRINT_REAL) {
- uid = getuid();
- gid = getgid();
+ if (!(option_mask32 & NAME_NOT_NUMBER) || !name) {
+ printf("%u", id);
+ }
+ if (!option_mask32 || (option_mask32 & NAME_NOT_NUMBER)) {
+ if (name) {
+ printf(option_mask32 ? "%s" : "(%s)", name);
} else {
- uid = geteuid();
- gid = getegid();
+ /* Don't set error status flag in default mode */
+ if (option_mask32) {
+ if (ENABLE_DESKTOP)
+ bb_error_msg("unknown ID %u", id);
+ return EXIT_FAILURE;
+ }
}
- my_getpwuid(user, uid);
+ }
+ return EXIT_SUCCESS;
+}
+
+static int print_group(gid_t id, const char *prefix)
+{
+ return print_common(id, gid2group(id), prefix);
+}
+
+static int print_user(uid_t id, const char *prefix)
+{
+ return print_common(id, uid2uname(id), prefix);
+}
+
+/* On error set *n < 0 and return >= 0
+ * If *n is too small, update it and return < 0
+ * (ok to trash groups[] in both cases)
+ * Otherwise fill in groups[] and return >= 0
+ */
+static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n)
+{
+ int m;
+
+ if (username) {
+ /* If the user is a member of more than
+ * *n groups, then -1 is returned. Otherwise >= 0.
+ * (and no defined way of detecting errors?!) */
+ m = getgrouplist(username, rgid, groups, n);
+ /* I guess *n < 0 might indicate error. Anyway,
+ * malloc'ing -1 bytes won't be good, so: */
+ //if (*n < 0)
+ // return 0;
+ //return m;
+ //commented out here, happens below anyway
} else {
- safe_strncpy(user, argv[optind], sizeof(user));
- gid = my_getpwnamegid(user);
+ /* On error -1 is returned, which ends up in *n */
+ int nn = getgroups(*n, groups);
+ /* 0: nn <= *n, groups[] was big enough; -1 otherwise */
+ m = - (nn > *n);
+ *n = nn;
}
- my_getgrgid(group, gid);
+ if (*n < 0)
+ return 0; /* error, don't return < 0! */
+ return m;
+}
- pwnam=my_getpwnam(user);
- grnam=my_getgrnam(group);
+int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int id_main(int argc UNUSED_PARAM, char **argv)
+{
+ uid_t ruid;
+ gid_t rgid;
+ uid_t euid;
+ gid_t egid;
+ unsigned opt;
+ int i;
+ int status = EXIT_SUCCESS;
+ const char *prefix;
+ const char *username;
+#if ENABLE_SELINUX
+ security_context_t scontext = NULL;
+#endif
+ /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
+ /* Don't allow more than one username */
+ opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG"
+ USE_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G");
+ opt = getopt32(argv, "rnugG" USE_SELINUX("Z"));
- if (flags & (JUST_GROUP | JUST_USER)) {
- char *s = group;
- if (flags & JUST_USER) {
- s = user;
- grnam = pwnam;
- }
- if (flags & NAME_NOT_NUMBER) {
- puts(s);
+ username = argv[optind];
+ if (username) {
+ struct passwd *p = xgetpwnam(username);
+ euid = ruid = p->pw_uid;
+ egid = rgid = p->pw_gid;
+ } else {
+ egid = getegid();
+ rgid = getgid();
+ euid = geteuid();
+ ruid = getuid();
+ }
+ /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */
+ /* id says: print the real ID instead of the effective ID, with -ugG */
+ /* in fact in this case egid is always printed if egid != rgid */
+ if (!opt || (opt & JUST_ALL_GROUPS)) {
+ gid_t *groups;
+ int n;
+
+ if (!opt) {
+ /* Default Mode */
+ status |= print_user(ruid, "uid=");
+ status |= print_group(rgid, " gid=");
+ if (euid != ruid)
+ status |= print_user(euid, " euid=");
+ if (egid != rgid)
+ status |= print_group(egid, " egid=");
} else {
- printf("%ld\n", grnam);
+ /* JUST_ALL_GROUPS */
+ status |= print_group(rgid, NULL);
+ if (egid != rgid)
+ status |= print_group(egid, " ");
}
- } else {
-#ifdef CONFIG_SELINUX
- printf("uid=%ld(%s) gid=%ld(%s)", pwnam, user, grnam, group);
- if(is_flask_enabled_flag)
- {
- security_id_t mysid = getsecsid();
- char context[80];
- int len = sizeof(context);
- context[0] = '\0';
- if(security_sid_to_context(mysid, context, &len))
- strcpy(context, "unknown");
- printf(" context=%s\n", context);
+ /* We are supplying largish buffer, trying
+ * to not run get_groups() twice. That might be slow
+ * ("user database in remote SQL server" case) */
+ groups = xmalloc(64 * sizeof(gid_t));
+ n = 64;
+ if (get_groups(username, rgid, groups, &n) < 0) {
+ /* Need bigger buffer after all */
+ groups = xrealloc(groups, n * sizeof(gid_t));
+ get_groups(username, rgid, groups, &n);
+ }
+ if (n > 0) {
+ /* Print the list */
+ prefix = " groups=";
+ for (i = 0; i < n; i++) {
+ if (opt && (groups[i] == rgid || groups[i] == egid))
+ continue;
+ status |= print_group(groups[i], opt ? " " : prefix);
+ prefix = ",";
+ }
+ } else if (n < 0) { /* error in get_groups() */
+ if (!ENABLE_DESKTOP)
+ bb_error_msg_and_die("cannot get groups");
+ else
+ return EXIT_FAILURE;
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(groups);
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ if (getcon(&scontext) == 0)
+ printf(" context=%s", scontext);
}
- else
- printf("\n");
-#else
- printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group);
#endif
-
+ } else if (opt & PRINT_REAL) {
+ euid = ruid;
+ egid = rgid;
}
- bb_fflush_stdout_and_exit(0);
+ if (opt & JUST_USER)
+ status |= print_user(euid, NULL);
+ else if (opt & JUST_GROUP)
+ status |= print_group(egid, NULL);
+#if ENABLE_SELINUX
+ else if (opt & JUST_CONTEXT) {
+ selinux_or_die();
+ if (username || getcon(&scontext)) {
+ bb_error_msg_and_die("can't get process context%s",
+ username ? " for a different user" : "");
+ }
+ fputs(scontext, stdout);
+ }
+ /* freecon(NULL) seems to be harmless */
+ if (ENABLE_FEATURE_CLEAN_UP)
+ freecon(scontext);
+#endif
+ bb_putchar('\n');
+ fflush_stdout_and_exit(status);
}
diff --git a/release/src/router/busybox/coreutils/id_test.sh b/release/src/router/busybox/coreutils/id_test.sh
new file mode 100755
index 00000000..0d65f2ae
--- /dev/null
+++ b/release/src/router/busybox/coreutils/id_test.sh
@@ -0,0 +1,244 @@
+#!/bin/bash
+# Test script for busybox id vs. coreutils id.
+# Needs root privileges for some tests.
+
+cp /usr/bin/id .
+BUSYBOX=./busybox
+ID=./id
+LIST=`awk -F: '{ printf "%s\n", $1 }' /etc/passwd`
+FLAG_USER_EXISTS="no"
+TEST_USER="f583ca884c1d93458fb61ed137ff44f6"
+
+echo "test 1: id [options] nousername"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+done
+
+echo "test 2: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ if test "$i" = "$TEST_USER"; then
+ FLAG_USER_EXISTS="yes"
+ fi
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+if test $FLAG_USER_EXISTS = "yes"; then
+ echo "test 3,4,5,6,7,8,9,10,11,12 skipped because test user $TEST_USER already exists"
+ rm -f foo bar
+ exit 1
+fi
+
+adduser -s /bin/true -g "" -H -D "$TEST_USER" || exit 1
+
+chown $TEST_USER.$TEST_USER $BUSYBOX
+chmod u+s $BUSYBOX 2>&1 /dev/null
+chown $TEST_USER.$TEST_USER $ID
+chmod u+s $ID 2>&1 /dev/null
+
+echo "test 3 setuid, existing user: id [options] no username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ #done
+done
+
+echo "test 4 setuid, existing user: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+chown $TEST_USER.$TEST_USER $BUSYBOX
+chmod g+s $BUSYBOX 2>&1 /dev/null
+chown $TEST_USER.$TEST_USER $ID
+chmod g+s $ID 2>&1 /dev/null
+
+echo "test 5 setgid, existing user: id [options] no username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ #done
+done
+
+echo "test 6 setgid, existing user: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+chown $TEST_USER.$TEST_USER $BUSYBOX
+chmod u+s,g+s $BUSYBOX 2>&1 /dev/null
+chown $TEST_USER.$TEST_USER $ID
+chmod u+s,g+s $ID 2>&1 /dev/null
+
+echo "test 7 setuid, setgid, existing user: id [options] no username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ #done
+done
+
+echo "test 8 setuid, setgid, existing user: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+deluser $TEST_USER || exit 1
+
+echo "test 9 setuid, setgid, not existing user: id [options] no username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+done
+
+echo "test 10 setuid, setgid, not existing user: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+chown .root $BUSYBOX 2>&1 /dev/null
+chown .root $ID 2>&1 /dev/null
+chmod g+s $BUSYBOX 2>&1 /dev/null
+chmod g+s $ID 2>&1 /dev/null
+
+echo "test 11 setgid, not existing group: id [options] no username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ $BUSYBOX id $OPTIONS >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ #done
+done
+
+echo "test 12 setgid, not existing group: id [options] username"
+rm -f foo bar
+for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr"
+do
+ #echo "$OPTIONS"
+ for i in $LIST ; do
+ $BUSYBOX id $OPTIONS $i >foo 2>/dev/null
+ RET1=$?
+ $ID $OPTIONS $i >bar 2>/dev/null
+ RET2=$?
+ if test "$RET1" != "$RET2"; then
+ echo "Return Values differ ($RET1 != $RET2): options $OPTIONS"
+ fi
+ diff foo bar
+ done
+done
+
+chown root.root $BUSYBOX 2>&1 /dev/null
+chown root.root $ID 2>&1 /dev/null
+rm -f $ID
+rm -f foo bar
diff --git a/release/src/router/busybox/coreutils/install.c b/release/src/router/busybox/coreutils/install.c
new file mode 100644
index 00000000..2b796e2a
--- /dev/null
+++ b/release/src/router/busybox/coreutils/install.c
@@ -0,0 +1,210 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 by Glenn McGrath
+ * SELinux support: by Yuichi Nakamura <ynakam@hitachisoft.jp>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+#include "libcoreutils/coreutils.h"
+
+#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
+static const char install_longopts[] ALIGN1 =
+ "directory\0" No_argument "d"
+ "preserve-timestamps\0" No_argument "p"
+ "strip\0" No_argument "s"
+ "group\0" Required_argument "g"
+ "mode\0" Required_argument "m"
+ "owner\0" Required_argument "o"
+/* autofs build insists of using -b --suffix=.orig */
+/* TODO? (short option for --suffix is -S) */
+#if ENABLE_SELINUX
+ "context\0" Required_argument "Z"
+ "preserve_context\0" No_argument "\xff"
+ "preserve-context\0" No_argument "\xff"
+#endif
+ ;
+#endif
+
+
+#if ENABLE_SELINUX
+static void setdefaultfilecon(const char *path)
+{
+ struct stat s;
+ security_context_t scontext = NULL;
+
+ if (!is_selinux_enabled()) {
+ return;
+ }
+ if (lstat(path, &s) != 0) {
+ return;
+ }
+
+ if (matchpathcon(path, s.st_mode, &scontext) < 0) {
+ goto out;
+ }
+ if (strcmp(scontext, "<<none>>") == 0) {
+ goto out;
+ }
+
+ if (lsetfilecon(path, scontext) < 0) {
+ if (errno != ENOTSUP) {
+ bb_perror_msg("warning: failed to change context"
+ " of %s to %s", path, scontext);
+ }
+ }
+
+ out:
+ freecon(scontext);
+}
+
+#endif
+
+int install_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int install_main(int argc, char **argv)
+{
+ struct stat statbuf;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ char *arg, *last;
+ const char *gid_str;
+ const char *uid_str;
+ const char *mode_str;
+ int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE;
+ int opts;
+ int min_args = 1;
+ int ret = EXIT_SUCCESS;
+ int isdir = 0;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+ bool use_default_selinux_context = 1;
+#endif
+ enum {
+ OPT_c = 1 << 0,
+ OPT_v = 1 << 1,
+ OPT_b = 1 << 2,
+ OPT_MKDIR_LEADING = 1 << 3,
+ OPT_DIRECTORY = 1 << 4,
+ OPT_PRESERVE_TIME = 1 << 5,
+ OPT_STRIP = 1 << 6,
+ OPT_GROUP = 1 << 7,
+ OPT_MODE = 1 << 8,
+ OPT_OWNER = 1 << 9,
+#if ENABLE_SELINUX
+ OPT_SET_SECURITY_CONTEXT = 1 << 10,
+ OPT_PRESERVE_SECURITY_CONTEXT = 1 << 11,
+#endif
+ };
+
+#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
+ applet_long_options = install_longopts;
+#endif
+ opt_complementary = "s--d:d--s" USE_SELINUX(":Z--\xff:\xff--Z");
+ /* -c exists for backwards compatibility, it's needed */
+ /* -v is ignored ("print name of each created directory") */
+ /* -b is ignored ("make a backup of each existing destination file") */
+ opts = getopt32(argv, "cvb" "Ddpsg:m:o:" USE_SELINUX("Z:"),
+ &gid_str, &mode_str, &uid_str USE_SELINUX(, &scontext));
+ argc -= optind;
+ argv += optind;
+
+#if ENABLE_SELINUX
+ if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) {
+ selinux_or_die();
+ use_default_selinux_context = 0;
+ if (opts & OPT_PRESERVE_SECURITY_CONTEXT) {
+ copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
+ }
+ if (opts & OPT_SET_SECURITY_CONTEXT) {
+ setfscreatecon_or_die(scontext);
+ copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT;
+ }
+ }
+#endif
+
+ /* preserve access and modification time, this is GNU behaviour,
+ * BSD only preserves modification time */
+ if (opts & OPT_PRESERVE_TIME) {
+ copy_flags |= FILEUTILS_PRESERVE_STATUS;
+ }
+ mode = 0666;
+ if (opts & OPT_MODE)
+ bb_parse_mode(mode_str, &mode);
+ uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid();
+ gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid();
+
+ last = argv[argc - 1];
+ if (!(opts & OPT_DIRECTORY)) {
+ argv[argc - 1] = NULL;
+ min_args++;
+
+ /* coreutils install resolves link in this case, don't use lstat */
+ isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode);
+ }
+
+ if (argc < min_args)
+ bb_show_usage();
+
+ while ((arg = *argv++) != NULL) {
+ char *dest = last;
+ if (opts & OPT_DIRECTORY) {
+ dest = arg;
+ /* GNU coreutils 6.9 does not set uid:gid
+ * on intermediate created directories
+ * (only on last one) */
+ if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) {
+ ret = EXIT_FAILURE;
+ goto next;
+ }
+ } else {
+ if (opts & OPT_MKDIR_LEADING) {
+ char *ddir = xstrdup(dest);
+ bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR);
+ /* errors are not checked. copy_file
+ * will fail if dir is not created. */
+ free(ddir);
+ }
+ if (isdir)
+ dest = concat_path_file(last, basename(arg));
+ if (copy_file(arg, dest, copy_flags)) {
+ /* copy is not made */
+ ret = EXIT_FAILURE;
+ goto next;
+ }
+ }
+
+ /* Set the file mode */
+ if ((opts & OPT_MODE) && chmod(dest, mode) == -1) {
+ bb_perror_msg("can't change %s of %s", "permissions", dest);
+ ret = EXIT_FAILURE;
+ }
+#if ENABLE_SELINUX
+ if (use_default_selinux_context)
+ setdefaultfilecon(dest);
+#endif
+ /* Set the user and group id */
+ if ((opts & (OPT_OWNER|OPT_GROUP))
+ && lchown(dest, uid, gid) == -1
+ ) {
+ bb_perror_msg("can't change %s of %s", "ownership", dest);
+ ret = EXIT_FAILURE;
+ }
+ if (opts & OPT_STRIP) {
+ char *args[3];
+ args[0] = (char*)"strip";
+ args[1] = dest;
+ args[2] = NULL;
+ if (spawn_and_wait(args)) {
+ bb_perror_msg("strip");
+ ret = EXIT_FAILURE;
+ }
+ }
+ next:
+ if (ENABLE_FEATURE_CLEAN_UP && isdir)
+ free(dest);
+ }
+
+ return ret;
+}
diff --git a/release/src/router/busybox/coreutils/length.c b/release/src/router/busybox/coreutils/length.c
index bce43ab3..43a0f598 100644
--- a/release/src/router/busybox/coreutils/length.c
+++ b/release/src/router/busybox/coreutils/length.c
@@ -1,19 +1,22 @@
/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
/* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "busybox.h"
+#include "libbb.h"
-extern int length_main(int argc, char **argv)
+/* This is a NOFORK applet. Be very careful! */
+
+int length_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int length_main(int argc, char **argv)
{
- if ((argc != 2) || (**(++argv) == '-')) {
- bb_show_usage();
+ if ((argc != 2) || (**(++argv) == '-')) {
+ bb_show_usage();
}
- bb_printf("%lu\n", (unsigned long)strlen(*argv));
+ printf("%u\n", (unsigned)strlen(*argv));
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ return fflush(stdout);
}
diff --git a/release/src/router/busybox/coreutils/libcoreutils/Kbuild b/release/src/router/busybox/coreutils/libcoreutils/Kbuild
new file mode 100644
index 00000000..755d01f8
--- /dev/null
+++ b/release/src/router/busybox/coreutils/libcoreutils/Kbuild
@@ -0,0 +1,12 @@
+# Makefile for busybox
+#
+# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+#
+# Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+
+lib-y:=
+lib-$(CONFIG_MKFIFO) += getopt_mk_fifo_nod.o
+lib-$(CONFIG_MKNOD) += getopt_mk_fifo_nod.o
+lib-$(CONFIG_INSTALL) += cp_mv_stat.o
+lib-$(CONFIG_CP) += cp_mv_stat.o
+lib-$(CONFIG_MV) += cp_mv_stat.o
diff --git a/release/src/router/busybox/coreutils/libcoreutils/Makefile b/release/src/router/busybox/coreutils/libcoreutils/Makefile
deleted file mode 100644
index b3a4e79b..00000000
--- a/release/src/router/busybox/coreutils/libcoreutils/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-TOPDIR:= ../../
-LIBCOREUTILS_DIR:=./
-include $(TOPDIR).config
-include $(TOPDIR)Rules.mak
-include Makefile.in
-all: $(libraries-y)
--include $(TOPDIR).depend
-
-clean:
- rm -f *.o *.a $(AR_TARGET)
-
diff --git a/release/src/router/busybox/coreutils/libcoreutils/Makefile.in b/release/src/router/busybox/coreutils/libcoreutils/Makefile.in
deleted file mode 100755
index a7481d40..00000000
--- a/release/src/router/busybox/coreutils/libcoreutils/Makefile.in
+++ /dev/null
@@ -1,32 +0,0 @@
-# Makefile for busybox
-#
-# Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-LIBCOREUTILS_AR:=libcoreutils.a
-ifndef $(LIBCOREUTILS_DIR)
-LIBCOREUTILS_DIR:=$(TOPDIR)coreutils/libcoreutils/
-endif
-
-LIBCOREUTILS_SRC:= cp_mv_stat.c getopt_mk_fifo_nod.c xgetoptfile_sort_uniq.c
-
-LIBCOREUTILS_OBJS=$(patsubst %.c,$(LIBCOREUTILS_DIR)%.o, $(LIBCOREUTILS_SRC))
-
-libraries-y+=$(LIBCOREUTILS_DIR)$(LIBCOREUTILS_AR)
-
-$(LIBCOREUTILS_DIR)$(LIBCOREUTILS_AR): $(LIBCOREUTILS_OBJS)
- $(AR) -ro $@ $(LIBCOREUTILS_OBJS)
diff --git a/release/src/router/busybox/coreutils/libcoreutils/coreutils.h b/release/src/router/busybox/coreutils/libcoreutils/coreutils.h
index eabca820..99b67b14 100644
--- a/release/src/router/busybox/coreutils/libcoreutils/coreutils.h
+++ b/release/src/router/busybox/coreutils/libcoreutils/coreutils.h
@@ -1,12 +1,20 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
#ifndef COREUTILS_H
-#define COREUTILS_H 1
+#define COREUTILS_H 1
+
+PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
typedef int (*stat_func)(const char *fn, struct stat *ps);
-extern int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf);
-extern int cp_mv_stat(const char *fn, struct stat *fn_stat);
+int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf) FAST_FUNC;
+int cp_mv_stat(const char *fn, struct stat *fn_stat) FAST_FUNC;
+
+mode_t getopt_mk_fifo_nod(char **argv) FAST_FUNC;
-extern mode_t getopt_mk_fifo_nod(int argc, char **argv);
-extern FILE *xgetoptfile_sort_uniq(char **argv, const char *mode);
+POP_SAVED_FUNCTION_VISIBILITY
#endif
diff --git a/release/src/router/busybox/coreutils/libcoreutils/cp_mv_stat.c b/release/src/router/busybox/coreutils/libcoreutils/cp_mv_stat.c
index 5a70b022..0fd467c3 100644
--- a/release/src/router/busybox/coreutils/libcoreutils/cp_mv_stat.c
+++ b/release/src/router/busybox/coreutils/libcoreutils/cp_mv_stat.c
@@ -20,26 +20,31 @@
*
*/
-#include <errno.h>
-#include <sys/stat.h>
#include "libbb.h"
#include "coreutils.h"
-extern int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf)
+int FAST_FUNC cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf)
{
if (sf(fn, fn_stat) < 0) {
if (errno != ENOENT) {
- bb_perror_msg("unable to stat `%s'", fn);
+#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE
+ if (errno == ENOTDIR) {
+ bb_error_msg("cannot stat '%s': Path has non-directory component", fn);
+ return -1;
+ }
+#endif
+ bb_perror_msg("cannot stat '%s'", fn);
return -1;
}
return 0;
- } else if (S_ISDIR(fn_stat->st_mode)) {
+ }
+ if (S_ISDIR(fn_stat->st_mode)) {
return 3;
}
return 1;
}
-extern int cp_mv_stat(const char *fn, struct stat *fn_stat)
+int FAST_FUNC cp_mv_stat(const char *fn, struct stat *fn_stat)
{
return cp_mv_stat2(fn, fn_stat, stat);
}
diff --git a/release/src/router/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c b/release/src/router/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c
index 0872bdcf..ba3222e4 100644
--- a/release/src/router/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c
+++ b/release/src/router/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c
@@ -20,26 +20,29 @@
*
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
#include "libbb.h"
#include "coreutils.h"
-extern mode_t getopt_mk_fifo_nod(int argc, char **argv)
+mode_t FAST_FUNC getopt_mk_fifo_nod(char **argv)
{
mode_t mode = 0666;
+ char *smode = NULL;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+#endif
int opt;
+ opt = getopt32(argv, "m:" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+ if (opt & 1) {
+ if (bb_parse_mode(smode, &mode))
+ umask(0);
+ }
- while ((opt = getopt(argc, argv, "m:")) > 0) {
- if (opt == 'm') {
- mode = 0666;
- if (bb_parse_mode(optarg, &mode)) {
- umask(0);
- continue;
- }
- }
- bb_show_usage();
+#if ENABLE_SELINUX
+ if (opt & 2) {
+ selinux_or_die();
+ setfscreatecon_or_die(scontext);
}
+#endif
+
return mode;
}
diff --git a/release/src/router/busybox/coreutils/libcoreutils/xgetoptfile_sort_uniq.c b/release/src/router/busybox/coreutils/libcoreutils/xgetoptfile_sort_uniq.c
deleted file mode 100644
index a63daf97..00000000
--- a/release/src/router/busybox/coreutils/libcoreutils/xgetoptfile_sort_uniq.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * coreutils utility routine
- *
- * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include "libbb.h"
-#include "coreutils.h"
-
-extern FILE *xgetoptfile_sort_uniq(char **argv, const char *mode)
-{
- const char *n;
-
- if ((n = *argv) != NULL) {
- if ((*n != '-') || n[1]) {
- return bb_xfopen(n, mode);
- }
- }
- return (*mode == 'r') ? stdin : stdout;
-}
diff --git a/release/src/router/busybox/coreutils/ln.c b/release/src/router/busybox/coreutils/ln.c
index 5217634f..eb717195 100644
--- a/release/src/router/busybox/coreutils/ln.c
+++ b/release/src/router/busybox/coreutils/ln.c
@@ -2,51 +2,39 @@
/*
* Mini ln implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
-/* BB_AUDIT GNU options missing: -b, -d, -F, -i, -S, and -v. */
+/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * Fixed bug involving -n option. Essentially, -n was always in effect.
- */
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
#define LN_SYMLINK 1
#define LN_FORCE 2
#define LN_NODEREFERENCE 4
+#define LN_BACKUP 8
+#define LN_SUFFIX 16
-extern int ln_main(int argc, char **argv)
+int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ln_main(int argc, char **argv)
{
int status = EXIT_SUCCESS;
int flag;
char *last;
char *src_name;
- const char *src;
+ char *src;
+ char *suffix = (char*)"~";
+ struct stat statbuf;
int (*link_func)(const char *, const char *);
- flag = bb_getopt_ulflags(argc, argv, "sfn");
+ flag = getopt32(argv, "sfnbS:", &suffix);
if (argc == optind) {
bb_show_usage();
@@ -57,23 +45,49 @@ extern int ln_main(int argc, char **argv)
if (argc == optind + 1) {
*--argv = last;
- last = bb_get_last_path_component(bb_xstrdup(last));
+ last = bb_get_last_path_component_strip(xstrdup(last));
}
do {
- src_name = 0;
+ src_name = NULL;
src = last;
if (is_directory(src,
- (flag & LN_NODEREFERENCE) ^ LN_NODEREFERENCE,
- NULL)) {
- src_name = bb_xstrdup(*argv);
- src = concat_path_file(src, bb_get_last_path_component(src_name));
+ (flag & LN_NODEREFERENCE) ^ LN_NODEREFERENCE,
+ NULL)
+ ) {
+ src_name = xstrdup(*argv);
+ src = concat_path_file(src, bb_get_last_path_component_strip(src_name));
free(src_name);
- src_name = (char *)src;
+ src_name = src;
+ }
+ if (!(flag & LN_SYMLINK) && stat(*argv, &statbuf)) {
+ // coreutils: "ln dangling_symlink new_hardlink" works
+ if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) {
+ bb_simple_perror_msg(*argv);
+ status = EXIT_FAILURE;
+ free(src_name);
+ continue;
+ }
}
- if (flag & LN_FORCE) {
+ if (flag & LN_BACKUP) {
+ char *backup;
+ backup = xasprintf("%s%s", src, suffix);
+ if (rename(src, backup) < 0 && errno != ENOENT) {
+ bb_simple_perror_msg(src);
+ status = EXIT_FAILURE;
+ free(backup);
+ continue;
+ }
+ free(backup);
+ /*
+ * When the source and dest are both hard links to the same
+ * inode, a rename may succeed even though nothing happened.
+ * Therefore, always unlink().
+ */
+ unlink(src);
+ } else if (flag & LN_FORCE) {
unlink(src);
}
@@ -81,25 +95,15 @@ extern int ln_main(int argc, char **argv)
if (flag & LN_SYMLINK) {
link_func = symlink;
}
-
+
if (link_func(*argv, src) != 0) {
- bb_perror_msg(src);
- status = EXIT_FAILURE;;
+ bb_simple_perror_msg(src);
+ status = EXIT_FAILURE;
}
free(src_name);
-
+
} while ((++argv)[1]);
return status;
}
-
-
-
-
-
-
-
-
-
-
diff --git a/release/src/router/busybox/coreutils/logname.c b/release/src/router/busybox/coreutils/logname.c
index 9cedff02..3400c30d 100644
--- a/release/src/router/busybox/coreutils/logname.c
+++ b/release/src/router/busybox/coreutils/logname.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2000 Edward Betts <edward@debian.org>.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
@@ -30,25 +17,26 @@
* is _not_ the same. Erik apparently made this change almost 3 years
* ago to avoid failing when no utmp was available. However, the
* correct course of action wrt SUSv3 for a failing getlogin() is
- * a dianostic message and an error return.
+ * a diagnostic message and an error return.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int logname_main(int argc, char **argv)
+int logname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int logname_main(int argc, char **argv UNUSED_PARAM)
{
- const char *p;
+ char buf[128];
if (argc > 1) {
bb_show_usage();
}
- if ((p = getlogin()) != NULL) {
- puts(p);
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ /* Using _r function - avoid pulling in static buffer from libc */
+ if (getlogin_r(buf, sizeof(buf)) == 0) {
+ puts(buf);
+ return fflush(stdout);
}
bb_perror_msg_and_die("getlogin");
diff --git a/release/src/router/busybox/coreutils/ls.c b/release/src/router/busybox/coreutils/ls.c
index a7f036b6..38957e93 100644
--- a/release/src/router/busybox/coreutils/ls.c
+++ b/release/src/router/busybox/coreutils/ls.c
@@ -3,22 +3,10 @@
* tiny-ls.c version 0.1.0: A minimalist 'ls'
* Copyright (C) 1996 Brian Candler <B.Candler@pobox.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.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-/*
+/* [date unknown. Perhaps before year 2000]
* To achieve a small memory footprint, this version of 'ls' doesn't do any
* file sorting, and only has the most essential command line switches
* (i.e., the ones I couldn't live without :-) All features which involve
@@ -30,8 +18,7 @@
*
* KNOWN BUGS:
* 1. ls -l of a directory doesn't give "total <blocks>" header
- * 2. ls of a symlink to a directory doesn't list directory contents
- * 3. hidden files can make column width too large
+ * 2. hidden files can make column width too large
*
* NON-OPTIMAL BEHAVIOUR:
* 1. autowidth reads directories twice
@@ -39,288 +26,409 @@
* appended, there's no need to stat each one
* PORTABILITY:
* 1. requires lstat (BSD) - how do you do it without?
+ *
+ * [2009-03]
+ * ls sorts listing now, and supports almost all options.
*/
-enum {
- TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */
- COLUMN_GAP = 2, /* includes the file type char */
-};
+#include "libbb.h"
-/************************************************************************/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include "busybox.h"
-#ifdef CONFIG_SELINUX
-#include <fs_secure.h>
-#include <flask_util.h>
-#include <ss.h>
+#if ENABLE_FEATURE_ASSUME_UNICODE
+#include <wchar.h>
#endif
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
-#include <time.h>
-#endif
+/* This is a NOEXEC applet. Be very careful! */
+
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
+#if ENABLE_FTPD
+/* ftpd uses ls, and without timestamps Mozilla won't understand
+ * ftpd's LIST output.
+ */
+# undef CONFIG_FEATURE_LS_TIMESTAMPS
+# undef ENABLE_FEATURE_LS_TIMESTAMPS
+# undef USE_FEATURE_LS_TIMESTAMPS
+# undef SKIP_FEATURE_LS_TIMESTAMPS
+# define CONFIG_FEATURE_LS_TIMESTAMPS 1
+# define ENABLE_FEATURE_LS_TIMESTAMPS 1
+# define USE_FEATURE_LS_TIMESTAMPS(...) __VA_ARGS__
+# define SKIP_FEATURE_LS_TIMESTAMPS(...)
#endif
-/* what is the overall style of the listing */
-#define STYLE_AUTO (0)
-#define STYLE_COLUMNS (1U<<21) /* fill columns */
-#define STYLE_LONG (2U<<21) /* one record per line, extended info */
-#define STYLE_SINGLE (3U<<21) /* one record per line */
-#define STYLE_MASK STYLE_SINGLE
-#define STYLE_ONE_RECORD_FLAG STYLE_LONG
+enum {
+
+TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */
+COLUMN_GAP = 2, /* includes the file type char */
+
+/* what is the overall style of the listing */
+STYLE_COLUMNS = 1 << 21, /* fill columns */
+STYLE_LONG = 2 << 21, /* one record per line, extended info */
+STYLE_SINGLE = 3 << 21, /* one record per line */
+STYLE_MASK = STYLE_SINGLE,
/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
/* what file information will be listed */
-#define LIST_INO (1U<<0)
-#define LIST_BLOCKS (1U<<1)
-#define LIST_MODEBITS (1U<<2)
-#define LIST_NLINKS (1U<<3)
-#define LIST_ID_NAME (1U<<4)
-#define LIST_ID_NUMERIC (1U<<5)
-#define LIST_CONTEXT (1U<<6)
-#define LIST_SIZE (1U<<7)
-#define LIST_DEV (1U<<8)
-#define LIST_DATE_TIME (1U<<9)
-#define LIST_FULLTIME (1U<<10)
-#define LIST_FILENAME (1U<<11)
-#define LIST_SYMLINK (1U<<12)
-#define LIST_FILETYPE (1U<<13)
-#define LIST_EXEC (1U<<14)
-
-#define LIST_MASK ((LIST_EXEC << 1) - 1)
+LIST_INO = 1 << 0,
+LIST_BLOCKS = 1 << 1,
+LIST_MODEBITS = 1 << 2,
+LIST_NLINKS = 1 << 3,
+LIST_ID_NAME = 1 << 4,
+LIST_ID_NUMERIC = 1 << 5,
+LIST_CONTEXT = 1 << 6,
+LIST_SIZE = 1 << 7,
+//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE
+LIST_DATE_TIME = 1 << 9,
+LIST_FULLTIME = 1 << 10,
+LIST_FILENAME = 1 << 11,
+LIST_SYMLINK = 1 << 12,
+LIST_FILETYPE = 1 << 13,
+LIST_EXEC = 1 << 14,
+LIST_MASK = (LIST_EXEC << 1) - 1,
/* what files will be displayed */
-/* TODO -- We may be able to make DISP_NORMAL 0 to save a bit slot. */
-#define DISP_NORMAL (1U<<14) /* show normal filenames */
-#define DISP_DIRNAME (1U<<15) /* 2 or more items? label directories */
-#define DISP_HIDDEN (1U<<16) /* show filenames starting with . */
-#define DISP_DOT (1U<<17) /* show . and .. */
-#define DISP_NOLIST (1U<<18) /* show directory as itself, not contents */
-#define DISP_RECURSIVE (1U<<19) /* show directory and everything below it */
-#define DISP_ROWS (1U<<20) /* print across rows */
-
-#define DISP_MASK (((DISP_ROWS << 1) - 1) & ~(DISP_NORMAL - 1))
-
-#ifdef CONFIG_FEATURE_LS_SORTFILES
-/* how will the files be sorted */
-#define SORT_ORDER_FORWARD 0 /* sort in reverse order */
-#define SORT_ORDER_REVERSE (1U<<27) /* sort in reverse order */
-
-#define SORT_NAME 0 /* sort by file name */
-#define SORT_SIZE (1U<<28) /* sort by file size */
-#define SORT_ATIME (2U<<28) /* sort by last access time */
-#define SORT_CTIME (3U<<28) /* sort by last change time */
-#define SORT_MTIME (4U<<28) /* sort by last modification time */
-#define SORT_VERSION (5U<<28) /* sort by version */
-#define SORT_EXT (6U<<28) /* sort by file name extension */
-#define SORT_DIR (7U<<28) /* sort by file or directory */
-
-#define SORT_MASK (7U<<28)
-#endif
+DISP_DIRNAME = 1 << 15, /* 2 or more items? label directories */
+DISP_HIDDEN = 1 << 16, /* show filenames starting with . */
+DISP_DOT = 1 << 17, /* show . and .. */
+DISP_NOLIST = 1 << 18, /* show directory as itself, not contents */
+DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */
+DISP_ROWS = 1 << 20, /* print across rows */
+DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1),
+
+/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */
+SORT_FORWARD = 0, /* sort in reverse order */
+SORT_REVERSE = 1 << 27, /* sort in reverse order */
+
+SORT_NAME = 0, /* sort by file name */
+SORT_SIZE = 1 << 28, /* sort by file size */
+SORT_ATIME = 2 << 28, /* sort by last access time */
+SORT_CTIME = 3 << 28, /* sort by last change time */
+SORT_MTIME = 4 << 28, /* sort by last modification time */
+SORT_VERSION = 5 << 28, /* sort by version */
+SORT_EXT = 6 << 28, /* sort by file name extension */
+SORT_DIR = 7 << 28, /* sort by file or directory */
+SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES,
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
/* which of the three times will be used */
-#define TIME_MOD 0
-#define TIME_CHANGE (1U<<23)
-#define TIME_ACCESS (1U<<24)
+TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
+TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS,
+TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
-#define TIME_MASK (3U<<23)
-#endif
+FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS,
-#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
-#define FOLLOW_LINKS (1U<<25)
-#endif
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
-#define LS_DISP_HR (1U<<26)
-#endif
+LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE,
-#define LIST_SHORT (LIST_FILENAME)
-#define LIST_ISHORT (LIST_INO | LIST_FILENAME)
-#define LIST_LONG (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
- LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK)
-#define LIST_ILONG (LIST_INO | LIST_LONG)
+LIST_SHORT = LIST_FILENAME,
+LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
+ LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK,
-#define SPLIT_DIR 1
-#define SPLIT_FILE 0
-#define SPLIT_SUBDIR 2
+SPLIT_DIR = 1,
+SPLIT_FILE = 0,
+SPLIT_SUBDIR = 2,
-#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
-#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+};
-#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR)
-# define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
-#endif
+/* "[-]Cadil1", POSIX mandated options, busybox always supports */
+/* "[-]gnsx", POSIX non-mandated options, busybox always supports */
+/* "[-]Q" GNU option? busybox always supports */
+/* "[-]Ak" GNU options, busybox always supports */
+/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */
+/* "[-]p", POSIX non-mandated options, busybox optionally supports */
+/* "[-]SXvThw", GNU options, busybox optionally supports */
+/* "[-]K", SELinux mandated options, busybox optionally supports */
+/* "[-]e", I think we made this one up */
+static const char ls_options[] ALIGN1 =
+ "Cadil1gnsxQAk" /* 13 opts, total 13 */
+ USE_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */
+ USE_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */
+ USE_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */
+ USE_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */
+ USE_FEATURE_LS_RECURSIVE("R") /* 1, 25 */
+ USE_FEATURE_HUMAN_READABLE("h") /* 1, 26 */
+ USE_SELINUX("KZ") /* 2, 28 */
+ USE_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */
+ ;
+enum {
+ //OPT_C = (1 << 0),
+ //OPT_a = (1 << 1),
+ //OPT_d = (1 << 2),
+ //OPT_i = (1 << 3),
+ //OPT_l = (1 << 4),
+ //OPT_1 = (1 << 5),
+ OPT_g = (1 << 6),
+ //OPT_n = (1 << 7),
+ //OPT_s = (1 << 8),
+ //OPT_x = (1 << 9),
+ OPT_Q = (1 << 10),
+ //OPT_A = (1 << 11),
+ //OPT_k = (1 << 12),
+ OPTBIT_color = 13
+ + 4 * ENABLE_FEATURE_LS_TIMESTAMPS
+ + 4 * ENABLE_FEATURE_LS_SORTFILES
+ + 2 * ENABLE_FEATURE_LS_FILETYPES
+ + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS
+ + 1 * ENABLE_FEATURE_LS_RECURSIVE
+ + 1 * ENABLE_FEATURE_HUMAN_READABLE
+ + 2 * ENABLE_SELINUX
+ + 2 * ENABLE_FEATURE_AUTOWIDTH,
+ OPT_color = 1 << OPTBIT_color,
+};
-/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
-#ifdef CONFIG_FEATURE_LS_COLOR
-static int show_color = 0;
+enum {
+ LIST_MASK_TRIGGER = 0,
+ STYLE_MASK_TRIGGER = STYLE_MASK,
+ DISP_MASK_TRIGGER = DISP_ROWS,
+ SORT_MASK_TRIGGER = SORT_MASK,
+};
-#define COLOR(mode) ("\000\043\043\043\042\000\043\043"\
- "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
-#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\
- "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
+/* TODO: simple toggles may be stored as OPT_xxx bits instead */
+static const unsigned opt_flags[] = {
+ LIST_SHORT | STYLE_COLUMNS, /* C */
+ DISP_HIDDEN | DISP_DOT, /* a */
+ DISP_NOLIST, /* d */
+ LIST_INO, /* i */
+ LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */
+ LIST_SHORT | STYLE_SINGLE, /* 1 */
+ 0, /* g (don't show group) - handled via OPT_g */
+ LIST_ID_NUMERIC, /* n */
+ LIST_BLOCKS, /* s */
+ DISP_ROWS, /* x */
+ 0, /* Q (quote filename) - handled via OPT_Q */
+ DISP_HIDDEN, /* A */
+ ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */
+ LIST_FULLTIME, /* e */
+ ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */
+ TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */
+#endif
+#if ENABLE_FEATURE_LS_SORTFILES
+ SORT_SIZE, /* S */
+ SORT_EXT, /* X */
+ SORT_REVERSE, /* r */
+ SORT_VERSION, /* v */
+#endif
+#if ENABLE_FEATURE_LS_FILETYPES
+ LIST_FILETYPE | LIST_EXEC, /* F */
+ LIST_FILETYPE, /* p */
+#endif
+#if ENABLE_FEATURE_LS_FOLLOWLINKS
+ FOLLOW_LINKS, /* L */
+#endif
+#if ENABLE_FEATURE_LS_RECURSIVE
+ DISP_RECURSIVE, /* R */
+#endif
+#if ENABLE_FEATURE_HUMAN_READABLE
+ LS_DISP_HR, /* h */
+#endif
+#if ENABLE_SELINUX
+ LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
+#endif
+#if ENABLE_SELINUX
+ LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */
#endif
+ (1U<<31)
+ /* options after Z are not processed through opt_flags:
+ * T, w - ignored
+ */
+};
+
/*
* a directory entry and its stat info are stored here
*/
-struct dnode { /* the basic node */
- char *name; /* the dir entry name */
- char *fullname; /* the dir entry name */
- struct stat dstat; /* the file stat info */
-#ifdef CONFIG_SELINUX
- security_id_t sid;
-#endif
- struct dnode *next; /* point at the next node */
+struct dnode { /* the basic node */
+ const char *name; /* the dir entry name */
+ const char *fullname; /* the dir entry name */
+ int allocated;
+ struct stat dstat; /* the file stat info */
+ USE_SELINUX(security_context_t sid;)
+ struct dnode *next; /* point at the next node */
};
-typedef struct dnode dnode_t;
static struct dnode **list_dir(const char *);
static struct dnode **dnalloc(int);
-static int list_single(struct dnode *);
+static int list_single(const struct dnode *);
-static unsigned int all_fmt;
-#ifdef CONFIG_SELINUX
-static int is_flask_enabled_flag;
+struct globals {
+#if ENABLE_FEATURE_LS_COLOR
+ smallint show_color;
#endif
+ smallint exit_code;
+ unsigned all_fmt;
+#if ENABLE_FEATURE_AUTOWIDTH
+ unsigned tabstops; // = COLUMN_GAP;
+ unsigned terminal_width; // = TERMINAL_WIDTH;
+#endif
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ /* Do time() just once. Saves one syscall per file for "ls -l" */
+ time_t current_time_t;
+#endif
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#if ENABLE_FEATURE_LS_COLOR
+#define show_color (G.show_color )
+#else
+enum { show_color = 0 };
+#endif
+#define exit_code (G.exit_code )
+#define all_fmt (G.all_fmt )
+#if ENABLE_FEATURE_AUTOWIDTH
+#define tabstops (G.tabstops )
+#define terminal_width (G.terminal_width)
+#else
+enum {
+ tabstops = COLUMN_GAP,
+ terminal_width = TERMINAL_WIDTH,
+};
+#endif
+#define current_time_t (G.current_time_t)
+/* memset: we have to zero it out because of NOEXEC */
+#define INIT_G() do { \
+ memset(&G, 0, sizeof(G)); \
+ USE_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \
+ USE_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \
+ USE_FEATURE_LS_TIMESTAMPS(time(&current_time_t);) \
+} while (0)
+
-#ifdef CONFIG_FEATURE_AUTOWIDTH
-static unsigned short terminal_width = TERMINAL_WIDTH;
-static unsigned short tabstops = COLUMN_GAP;
+#if ENABLE_FEATURE_ASSUME_UNICODE
+/* libbb candidate */
+static size_t mbstrlen(const char *string)
+{
+ size_t width = mbsrtowcs(NULL /*dest*/, &string,
+ MAXINT(size_t) /*len*/, NULL /*state*/);
+ if (width == (size_t)-1)
+ return strlen(string);
+ return width;
+}
#else
-#define tabstops COLUMN_GAP
-#define terminal_width TERMINAL_WIDTH
+#define mbstrlen(string) strlen(string)
#endif
-static int status = EXIT_SUCCESS;
-static struct dnode *my_stat(char *fullname, char *name)
+static struct dnode *my_stat(const char *fullname, const char *name, int force_follow)
{
struct stat dstat;
struct dnode *cur;
-#ifdef CONFIG_SELINUX
- security_id_t sid;
-#endif
- int rc;
+ USE_SELINUX(security_context_t sid = NULL;)
-#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
- if (all_fmt & FOLLOW_LINKS) {
-#ifdef CONFIG_SELINUX
- if(is_flask_enabled_flag)
- rc = stat_secure(fullname, &dstat, &sid);
- else
+ if ((all_fmt & FOLLOW_LINKS) || force_follow) {
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ getfilecon(fullname, &sid);
+ }
#endif
- rc = stat(fullname, &dstat);
- if(rc)
- {
- bb_perror_msg("%s", fullname);
- status = EXIT_FAILURE;
+ if (stat(fullname, &dstat)) {
+ bb_simple_perror_msg(fullname);
+ exit_code = EXIT_FAILURE;
return 0;
}
- } else
-#endif
- {
-#ifdef CONFIG_SELINUX
- if(is_flask_enabled_flag)
- rc = lstat_secure(fullname, &dstat, &sid);
- else
+ } else {
+#if ENABLE_SELINUX
+ if (is_selinux_enabled()) {
+ lgetfilecon(fullname, &sid);
+ }
#endif
- rc = lstat(fullname, &dstat);
- if(rc)
- {
- bb_perror_msg("%s", fullname);
- status = EXIT_FAILURE;
+ if (lstat(fullname, &dstat)) {
+ bb_simple_perror_msg(fullname);
+ exit_code = EXIT_FAILURE;
return 0;
}
}
- cur = (struct dnode *) xmalloc(sizeof(struct dnode));
+ cur = xmalloc(sizeof(struct dnode));
cur->fullname = fullname;
cur->name = name;
cur->dstat = dstat;
-#ifdef CONFIG_SELINUX
- cur->sid = sid;
-#endif
+ USE_SELINUX(cur->sid = sid;)
return cur;
}
-/*----------------------------------------------------------------------*/
-#ifdef CONFIG_FEATURE_LS_COLOR
+
+/* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket
+ * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file
+ * 3/7:multiplexed char/block device)
+ * and we use 0 for unknown and 15 for executables (see below) */
+#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
+#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
+#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
+/* 036 black foreground 050 black background
+ 037 red foreground 051 red background
+ 040 green foreground 052 green background
+ 041 brown foreground 053 brown background
+ 042 blue foreground 054 blue background
+ 043 magenta (purple) foreground 055 magenta background
+ 044 cyan (light blue) foreground 056 cyan background
+ 045 gray foreground 057 white background
+*/
+#define COLOR(mode) ( \
+ /*un fi chr dir blk file link sock exe */ \
+ "\037\043\043\045\042\045\043\043\000\045\044\045\043\045\045\040" \
+ [TYPEINDEX(mode)])
+/* Select normal (0) [actually "reset all"] or bold (1)
+ * (other attributes are 2:dim 4:underline 5:blink 7:reverse,
+ * let's use 7 for "impossible" types, just for fun)
+ * Note: coreutils 6.9 uses inverted red for setuid binaries.
+ */
+#define ATTR(mode) ( \
+ /*un fi chr dir blk file link sock exe */ \
+ "\01\00\01\07\01\07\01\07\00\07\01\07\01\07\07\01" \
+ [TYPEINDEX(mode)])
+
+#if ENABLE_FEATURE_LS_COLOR
+/* mode of zero is interpreted as "unknown" (stat failed) */
static char fgcolor(mode_t mode)
{
- /* Check wheter the file is existing (if so, color it red!) */
- if (errno == ENOENT) {
- return '\037';
- }
- if (LIST_EXEC && S_ISREG(mode)
- && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
return COLOR(0xF000); /* File is executable ... */
return COLOR(mode);
}
-
-/*----------------------------------------------------------------------*/
-static char bgcolor(mode_t mode)
+static char bold(mode_t mode)
{
- if (LIST_EXEC && S_ISREG(mode)
- && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
return ATTR(0xF000); /* File is executable ... */
return ATTR(mode);
}
#endif
-/*----------------------------------------------------------------------*/
-#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR)
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
static char append_char(mode_t mode)
{
if (!(all_fmt & LIST_FILETYPE))
return '\0';
- if ((all_fmt & LIST_EXEC) && S_ISREG(mode)
- && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ if (S_ISDIR(mode))
+ return '/';
+ if (!(all_fmt & LIST_EXEC))
+ return '\0';
+ if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
return '*';
return APPCHAR(mode);
}
#endif
-/*----------------------------------------------------------------------*/
-
-#define countdirs(A,B) count_dirs((A), (B), 1)
-#define countsubdirs(A,B) count_dirs((A), (B), 0)
+#define countdirs(A, B) count_dirs((A), (B), 1)
+#define countsubdirs(A, B) count_dirs((A), (B), 0)
static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs)
{
int i, dirs;
- if (dn == NULL || nfiles < 1)
- return (0);
+ if (!dn)
+ return 0;
dirs = 0;
for (i = 0; i < nfiles; i++) {
- if (S_ISDIR(dn[i]->dstat.st_mode)
- && (notsubdirs
- || ((dn[i]->name[0] != '.')
- || (dn[i]->name[1]
- && ((dn[i]->name[1] != '.')
- || dn[i]->name[2])))))
+ const char *name;
+ if (!S_ISDIR(dn[i]->dstat.st_mode))
+ continue;
+ name = dn[i]->name;
+ if (notsubdirs
+ || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
+ ) {
dirs++;
+ }
}
- return (dirs);
+ return dirs;
}
static int countfiles(struct dnode **dnp)
@@ -329,44 +437,41 @@ static int countfiles(struct dnode **dnp)
struct dnode *cur;
if (dnp == NULL)
- return (0);
+ return 0;
nfiles = 0;
- for (cur = dnp[0]; cur->next != NULL; cur = cur->next)
+ for (cur = dnp[0]; cur->next; cur = cur->next)
nfiles++;
nfiles++;
- return (nfiles);
+ return nfiles;
}
/* get memory to hold an array of pointers */
static struct dnode **dnalloc(int num)
{
- struct dnode **p;
-
if (num < 1)
- return (NULL);
+ return NULL;
- p = (struct dnode **) xcalloc((size_t) num,
- (size_t) (sizeof(struct dnode *)));
- return (p);
+ return xzalloc(num * sizeof(struct dnode *));
}
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
-static void dfree(struct dnode **dnp)
+#if ENABLE_FEATURE_LS_RECURSIVE
+static void dfree(struct dnode **dnp, int nfiles)
{
- struct dnode *cur, *next;
+ int i;
if (dnp == NULL)
return;
- cur = dnp[0];
- while (cur != NULL) {
- free(cur->fullname); /* free the filename */
- next = cur->next;
+ for (i = 0; i < nfiles; i++) {
+ struct dnode *cur = dnp[i];
+ if (cur->allocated)
+ free((char*)cur->fullname); /* free the filename */
free(cur); /* free the dnode */
- cur = next;
}
free(dnp); /* free the array holding the dnode pointers */
}
+#else
+#define dfree(...) ((void)0)
#endif
static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
@@ -375,7 +480,7 @@ static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
struct dnode **dnp;
if (dn == NULL || nfiles < 1)
- return (NULL);
+ return NULL;
/* count how many dirs and regular files there are */
if (which == SPLIT_SUBDIR)
@@ -392,30 +497,33 @@ static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
/* copy the entrys into the file or dir array */
for (d = i = 0; i < nfiles; i++) {
if (S_ISDIR(dn[i]->dstat.st_mode)) {
- if (which & (SPLIT_DIR|SPLIT_SUBDIR)) {
- if ((which & SPLIT_DIR)
- || ((dn[i]->name[0] != '.')
- || (dn[i]->name[1]
- && ((dn[i]->name[1] != '.')
- || dn[i]->name[2])))) {
- dnp[d++] = dn[i];
- }
+ const char *name;
+ if (!(which & (SPLIT_DIR|SPLIT_SUBDIR)))
+ continue;
+ name = dn[i]->name;
+ if ((which & SPLIT_DIR)
+ || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
+ ) {
+ dnp[d++] = dn[i];
}
} else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) {
dnp[d++] = dn[i];
}
}
- return (dnp);
+ return dnp;
}
-/*----------------------------------------------------------------------*/
-#ifdef CONFIG_FEATURE_LS_SORTFILES
-static int sortcmp(struct dnode *d1, struct dnode *d2)
+#if ENABLE_FEATURE_LS_SORTFILES
+static int sortcmp(const void *a, const void *b)
{
- unsigned int sort_opts = all_fmt & SORT_MASK;
+ struct dnode *d1 = *(struct dnode **)a;
+ struct dnode *d2 = *(struct dnode **)b;
+ unsigned sort_opts = all_fmt & SORT_MASK;
int dif;
- dif = 0; /* assume SORT_NAME */
+ dif = 0; /* assume SORT_NAME */
+ // TODO: use pre-initialized function pointer
+ // instead of branch forest
if (sort_opts == SORT_SIZE) {
dif = (int) (d2->dstat.st_size - d1->dstat.st_size);
} else if (sort_opts == SORT_ATIME) {
@@ -431,46 +539,26 @@ static int sortcmp(struct dnode *d1, struct dnode *d2)
}
if (dif == 0) {
- /* sort by name- may be a tie_breaker for time or size cmp */
-#ifdef CONFIG_LOCALE_SUPPORT
- dif = strcoll(d1->name, d2->name);
-#else
- dif = strcmp(d1->name, d2->name);
-#endif
+ /* sort by name - may be a tie_breaker for time or size cmp */
+ if (ENABLE_LOCALE_SUPPORT) dif = strcoll(d1->name, d2->name);
+ else dif = strcmp(d1->name, d2->name);
}
- if (all_fmt & SORT_ORDER_REVERSE) {
+ if (all_fmt & SORT_REVERSE) {
dif = -dif;
}
- return (dif);
+ return dif;
}
-/*----------------------------------------------------------------------*/
-static void shellsort(struct dnode **dn, int size)
+static void dnsort(struct dnode **dn, int size)
{
- struct dnode *temp;
- int gap, i, j;
-
- /* shell short the array */
- if (dn == NULL || size < 2)
- return;
-
- for (gap = size / 2; gap > 0; gap /= 2) {
- for (i = gap; i < size; i++) {
- for (j = i - gap; j >= 0; j -= gap) {
- if (sortcmp(dn[j], dn[j + gap]) <= 0)
- break;
- /* they are out of order, swap them */
- temp = dn[j];
- dn[j] = dn[j + gap];
- dn[j + gap] = temp;
- }
- }
- }
+ qsort(dn, size, sizeof(*dn), sortcmp);
}
+#else
+#define dnsort(dn, size) ((void)0)
#endif
-/*----------------------------------------------------------------------*/
+
static void showfiles(struct dnode **dn, int nfiles)
{
int i, ncols, nrows, row, nc;
@@ -481,27 +569,25 @@ static void showfiles(struct dnode **dn, int nfiles)
if (dn == NULL || nfiles < 1)
return;
- if (all_fmt & STYLE_ONE_RECORD_FLAG) {
+ if (all_fmt & STYLE_LONG) {
ncols = 1;
} else {
- /* find the longest file name- use that as the column width */
+ /* find the longest file name, use that as the column width */
for (i = 0; i < nfiles; i++) {
- int len = strlen(dn[i]->name) +
-#ifdef CONFIG_SELINUX
- ((all_fmt & LIST_CONTEXT) ? 33 : 0) +
-#endif
- ((all_fmt & LIST_INO) ? 8 : 0) +
- ((all_fmt & LIST_BLOCKS) ? 5 : 0);
+ int len = mbstrlen(dn[i]->name);
if (column_width < len)
column_width = len;
}
- column_width += tabstops;
+ column_width += tabstops +
+ USE_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
+ ((all_fmt & LIST_INO) ? 8 : 0) +
+ ((all_fmt & LIST_BLOCKS) ? 5 : 0);
ncols = (int) (terminal_width / column_width);
}
if (ncols > 1) {
nrows = nfiles / ncols;
- if ((nrows * ncols) < nfiles)
+ if (nrows * ncols < nfiles)
nrows++; /* round up fractionals */
} else {
nrows = nfiles;
@@ -517,66 +603,62 @@ static void showfiles(struct dnode **dn, int nfiles)
if (i < nfiles) {
if (column > 0) {
nexttab -= column;
- while (nexttab--) {
- putchar(' ');
- column++;
- }
- }
+ printf("%*s", nexttab, "");
+ column += nexttab;
+ }
nexttab = column + column_width;
column += list_single(dn[i]);
- }
+ }
}
putchar('\n');
column = 0;
}
}
-/*----------------------------------------------------------------------*/
-static void showdirs(struct dnode **dn, int ndirs)
+
+static void showdirs(struct dnode **dn, int ndirs, int first)
{
int i, nfiles;
struct dnode **subdnp;
-
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
int dndirs;
struct dnode **dnd;
-#endif
if (dn == NULL || ndirs < 1)
return;
for (i = 0; i < ndirs; i++) {
if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
- printf("\n%s:\n", dn[i]->fullname);
+ if (!first)
+ bb_putchar('\n');
+ first = 0;
+ printf("%s:\n", dn[i]->fullname);
}
subdnp = list_dir(dn[i]->fullname);
nfiles = countfiles(subdnp);
if (nfiles > 0) {
/* list all files at this level */
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- shellsort(subdnp, nfiles);
-#endif
+ dnsort(subdnp, nfiles);
showfiles(subdnp, nfiles);
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
- if (all_fmt & DISP_RECURSIVE) {
- /* recursive- list the sub-dirs */
- dnd = splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
- dndirs = countsubdirs(subdnp, nfiles);
- if (dndirs > 0) {
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- shellsort(dnd, dndirs);
-#endif
- showdirs(dnd, dndirs);
- free(dnd); /* free the array of dnode pointers to the dirs */
+ if (ENABLE_FEATURE_LS_RECURSIVE) {
+ if (all_fmt & DISP_RECURSIVE) {
+ /* recursive- list the sub-dirs */
+ dnd = splitdnarray(subdnp, nfiles, SPLIT_SUBDIR);
+ dndirs = countsubdirs(subdnp, nfiles);
+ if (dndirs > 0) {
+ dnsort(dnd, dndirs);
+ showdirs(dnd, dndirs, 0);
+ /* free the array of dnode pointers to the dirs */
+ free(dnd);
+ }
}
+ /* free the dnodes and the fullname mem */
+ dfree(subdnp, nfiles);
}
- dfree(subdnp); /* free the dnodes and the fullname mem */
-#endif
}
}
}
-/*----------------------------------------------------------------------*/
+
static struct dnode **list_dir(const char *path)
{
struct dnode *dn, *cur, **dnp;
@@ -585,33 +667,35 @@ static struct dnode **list_dir(const char *path)
int i, nfiles;
if (path == NULL)
- return (NULL);
+ return NULL;
dn = NULL;
nfiles = 0;
- dir = opendir(path);
+ dir = warn_opendir(path);
if (dir == NULL) {
- bb_perror_msg("%s", path);
- status = EXIT_FAILURE;
- return (NULL); /* could not open the dir */
+ exit_code = EXIT_FAILURE;
+ return NULL; /* could not open the dir */
}
while ((entry = readdir(dir)) != NULL) {
char *fullname;
/* are we going to list the file- it may be . or .. or a hidden file */
if (entry->d_name[0] == '.') {
- if ((entry->d_name[1] == 0 || (
- entry->d_name[1] == '.'
- && entry->d_name[2] == 0))
- && !(all_fmt & DISP_DOT))
- continue;
+ if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2]))
+ && !(all_fmt & DISP_DOT)
+ ) {
+ continue;
+ }
if (!(all_fmt & DISP_HIDDEN))
- continue;
+ continue;
}
fullname = concat_path_file(path, entry->d_name);
- cur = my_stat(fullname, strrchr(fullname, '/') + 1);
- if (!cur)
+ cur = my_stat(fullname, bb_basename(fullname), 0);
+ if (!cur) {
+ free(fullname);
continue;
+ }
+ cur->allocated = 1;
cur->next = dn;
dn = cur;
nfiles++;
@@ -619,40 +703,68 @@ static struct dnode **list_dir(const char *path)
closedir(dir);
/* now that we know how many files there are
- ** allocate memory for an array to hold dnode pointers
+ * allocate memory for an array to hold dnode pointers
*/
if (dn == NULL)
- return (NULL);
+ return NULL;
dnp = dnalloc(nfiles);
for (i = 0, cur = dn; i < nfiles; i++) {
dnp[i] = cur; /* save pointer to node in array */
cur = cur->next;
}
- return (dnp);
+ return dnp;
}
-/*----------------------------------------------------------------------*/
-static int list_single(struct dnode *dn)
-{
- int i, column = 0;
-#ifdef CONFIG_FEATURE_LS_USERNAME
- char scratch[16];
+static int print_name(const char *name)
+{
+ if (option_mask32 & OPT_Q) {
+#if ENABLE_FEATURE_ASSUME_UNICODE
+ int len = 2 + mbstrlen(name);
+#else
+ int len = 2;
#endif
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
+ putchar('"');
+ while (*name) {
+ if (*name == '"') {
+ putchar('\\');
+ len++;
+ }
+ putchar(*name++);
+ if (!ENABLE_FEATURE_ASSUME_UNICODE)
+ len++;
+ }
+ putchar('"');
+ return len;
+ }
+ /* No -Q: */
+#if ENABLE_FEATURE_ASSUME_UNICODE
+ fputs(name, stdout);
+ return mbstrlen(name);
+#else
+ return printf("%s", name);
+#endif
+}
+
+
+static int list_single(const struct dnode *dn)
+{
+ int column = 0;
+ char *lpath = lpath; /* for compiler */
+#if ENABLE_FEATURE_LS_TIMESTAMPS
char *filetime;
time_t ttime, age;
#endif
-#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined (CONFIG_FEATURE_LS_COLOR)
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
struct stat info;
char append;
#endif
if (dn->fullname == NULL)
- return (0);
+ return 0;
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
+#if ENABLE_FEATURE_LS_TIMESTAMPS
ttime = dn->dstat.st_mtime; /* the default time */
if (all_fmt & TIME_ACCESS)
ttime = dn->dstat.st_atime;
@@ -660,70 +772,65 @@ static int list_single(struct dnode *dn)
ttime = dn->dstat.st_ctime;
filetime = ctime(&ttime);
#endif
-#ifdef CONFIG_FEATURE_LS_FILETYPES
+#if ENABLE_FEATURE_LS_FILETYPES
append = append_char(dn->dstat.st_mode);
#endif
- for (i = 0; i <= 31; i++) {
- switch (all_fmt & (1 << i)) {
- case LIST_INO:
- column += printf("%7ld ", (long int) dn->dstat.st_ino);
- break;
- case LIST_BLOCKS:
-#if _FILE_OFFSET_BITS == 64
- column += printf("%4lld ", dn->dstat.st_blocks >> 1);
-#else
- column += printf("%4ld ", dn->dstat.st_blocks >> 1);
-#endif
- break;
- case LIST_MODEBITS:
- column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
- break;
- case LIST_NLINKS:
- column += printf("%4ld ", (long) dn->dstat.st_nlink);
- break;
- case LIST_ID_NAME:
-#ifdef CONFIG_FEATURE_LS_USERNAME
- my_getpwuid(scratch, dn->dstat.st_uid);
- printf("%-8.8s ", scratch);
- my_getgrgid(scratch, dn->dstat.st_gid);
- printf("%-8.8s", scratch);
- column += 17;
- break;
+ /* Do readlink early, so that if it fails, error message
+ * does not appear *inside* of the "ls -l" line */
+ if (all_fmt & LIST_SYMLINK)
+ if (S_ISLNK(dn->dstat.st_mode))
+ lpath = xmalloc_readlink_or_warn(dn->fullname);
+
+ if (all_fmt & LIST_INO)
+ column += printf("%7lu ", (long) dn->dstat.st_ino);
+ if (all_fmt & LIST_BLOCKS)
+ column += printf("%4"OFF_FMT"u ", (off_t) dn->dstat.st_blocks >> 1);
+ if (all_fmt & LIST_MODEBITS)
+ column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode));
+ if (all_fmt & LIST_NLINKS)
+ column += printf("%4lu ", (long) dn->dstat.st_nlink);
+#if ENABLE_FEATURE_LS_USERNAME
+ if (all_fmt & LIST_ID_NAME) {
+ if (option_mask32 & OPT_g) {
+ column += printf("%-8.8s",
+ get_cached_username(dn->dstat.st_uid));
+ } else {
+ column += printf("%-8.8s %-8.8s",
+ get_cached_username(dn->dstat.st_uid),
+ get_cached_groupname(dn->dstat.st_gid));
+ }
+ }
#endif
- case LIST_ID_NUMERIC:
- column += printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid);
- break;
- case LIST_SIZE:
- case LIST_DEV:
- if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
- column += printf("%4d, %3d ", (int) MAJOR(dn->dstat.st_rdev),
- (int) MINOR(dn->dstat.st_rdev));
+ if (all_fmt & LIST_ID_NUMERIC) {
+ if (option_mask32 & OPT_g)
+ column += printf("%-8u", (int) dn->dstat.st_uid);
+ else
+ column += printf("%-8u %-8u",
+ (int) dn->dstat.st_uid,
+ (int) dn->dstat.st_gid);
+ }
+ if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) {
+ if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) {
+ column += printf("%4u, %3u ",
+ (int) major(dn->dstat.st_rdev),
+ (int) minor(dn->dstat.st_rdev));
+ } else {
+ if (all_fmt & LS_DISP_HR) {
+ column += printf("%9s ",
+ make_human_readable_str(dn->dstat.st_size, 1, 0));
} else {
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- if (all_fmt & LS_DISP_HR) {
- column += printf("%9s ",
- make_human_readable_str(dn->dstat.st_size, 1, 0));
- } else
-#endif
- {
-#if _FILE_OFFSET_BITS == 64
- column += printf("%9lld ", (long long) dn->dstat.st_size);
-#else
- column += printf("%9ld ", dn->dstat.st_size);
-#endif
- }
- }
- break;
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
- case LIST_FULLTIME:
- case LIST_DATE_TIME:
- if (all_fmt & LIST_FULLTIME) {
- printf("%24.24s ", filetime);
- column += 25;
- break;
+ column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size);
}
- age = time(NULL) - ttime;
+ }
+ }
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ if (all_fmt & LIST_FULLTIME)
+ column += printf("%24.24s ", filetime);
+ if (all_fmt & LIST_DATE_TIME)
+ if ((all_fmt & LIST_FULLTIME) == 0) {
+ /* current_time_t ~== time(NULL) */
+ age = current_time_t - ttime;
printf("%6.6s ", filetime + 4);
if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
/* hh:mm if less than 6 months old */
@@ -732,332 +839,209 @@ static int list_single(struct dnode *dn)
printf(" %4.4s ", filetime + 20);
}
column += 13;
- break;
+ }
#endif
-#ifdef CONFIG_SELINUX
- case LIST_CONTEXT:
- {
- char context[64];
- int len = sizeof(context);
- if(security_sid_to_context(dn->sid, context, &len))
- {
- strcpy(context, "unknown");
- len = 7;
- }
- printf("%-32s ", context);
- column += MAX(33, len);
+#if ENABLE_SELINUX
+ if (all_fmt & LIST_CONTEXT) {
+ column += printf("%-32s ", dn->sid ? dn->sid : "unknown");
+ freecon(dn->sid);
+ }
+#endif
+ if (all_fmt & LIST_FILENAME) {
+#if ENABLE_FEATURE_LS_COLOR
+ if (show_color) {
+ info.st_mode = 0; /* for fgcolor() */
+ lstat(dn->fullname, &info);
+ printf("\033[%u;%um", bold(info.st_mode),
+ fgcolor(info.st_mode));
+ }
+#endif
+ column += print_name(dn->name);
+ if (show_color) {
+ printf("\033[0m");
+ }
+ }
+ if (all_fmt & LIST_SYMLINK) {
+ if (S_ISLNK(dn->dstat.st_mode) && lpath) {
+ printf(" -> ");
+#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
+#if ENABLE_FEATURE_LS_COLOR
+ info.st_mode = 0; /* for fgcolor() */
+#endif
+ if (stat(dn->fullname, &info) == 0) {
+ append = append_char(info.st_mode);
}
- break;
#endif
- case LIST_FILENAME:
-#ifdef CONFIG_FEATURE_LS_COLOR
- errno = 0;
- if (show_color && !lstat(dn->fullname, &info)) {
- printf("\033[%d;%dm", bgcolor(info.st_mode),
+#if ENABLE_FEATURE_LS_COLOR
+ if (show_color) {
+ printf("\033[%u;%um", bold(info.st_mode),
fgcolor(info.st_mode));
}
#endif
- column += printf("%s", dn->name);
-#ifdef CONFIG_FEATURE_LS_COLOR
+ column += print_name(lpath) + 4;
if (show_color) {
printf("\033[0m");
}
-#endif
- break;
- case LIST_SYMLINK:
- if (S_ISLNK(dn->dstat.st_mode)) {
- char *lpath = xreadlink(dn->fullname);
-
- if (lpath) {
- printf(" -> ");
-#if defined(CONFIG_FEATURE_LS_FILETYPES) || defined (CONFIG_FEATURE_LS_COLOR)
- if (!stat(dn->fullname, &info)) {
- append = append_char(info.st_mode);
- }
-#endif
-#ifdef CONFIG_FEATURE_LS_COLOR
- if (show_color) {
- errno = 0;
- printf("\033[%d;%dm", bgcolor(info.st_mode),
- fgcolor(info.st_mode));
- }
-#endif
- column += printf("%s", lpath) + 4;
-#ifdef CONFIG_FEATURE_LS_COLOR
- if (show_color) {
- printf("\033[0m");
- }
-#endif
- free(lpath);
- }
- }
- break;
-#ifdef CONFIG_FEATURE_LS_FILETYPES
- case LIST_FILETYPE:
- if (append != '\0') {
- printf("%1c", append);
- column++;
- }
- break;
-#endif
+ free(lpath);
}
}
+#if ENABLE_FEATURE_LS_FILETYPES
+ if (all_fmt & LIST_FILETYPE) {
+ if (append) {
+ putchar(append);
+ column++;
+ }
+ }
+#endif
return column;
}
-/*----------------------------------------------------------------------*/
-
-static const char ls_opts[] = "1AaCdgilnsx"
-#ifdef CONFIG_FEATURE_LS_FILETYPES
- "Fp"
-#endif
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
- "R"
-#endif
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- "rSvX"
-#endif
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
- "ecut"
-#endif
-#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
- "L"
-#endif
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- "h"
-#endif
- "k"
-#ifdef CONFIG_SELINUX
- "K"
-#endif
-#ifdef CONFIG_FEATURE_AUTOWIDTH
- "T:w:"
-#endif
- ;
-
-#define LIST_MASK_TRIGGER LIST_SHORT
-#define STYLE_MASK_TRIGGER STYLE_MASK
-#define SORT_MASK_TRIGGER SORT_MASK
-#define DISP_MASK_TRIGGER DISP_ROWS
-#define TIME_MASK_TRIGGER TIME_MASK
-
-static const unsigned opt_flags[] = {
- LIST_SHORT | STYLE_SINGLE, /* 1 */
- DISP_HIDDEN, /* A */
- DISP_HIDDEN | DISP_DOT, /* a */
- LIST_SHORT | STYLE_COLUMNS, /* C */
- DISP_NOLIST, /* d */
- 0, /* g - ingored */
- LIST_INO, /* i */
- LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */
- LIST_ID_NUMERIC, /* n */
- LIST_BLOCKS, /* s */
- DISP_ROWS, /* x */
-#ifdef CONFIG_FEATURE_LS_FILETYPES
- LIST_FILETYPE | LIST_EXEC, /* F */
- LIST_FILETYPE, /* p */
-#endif
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
- DISP_RECURSIVE, /* R */
-#endif
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- SORT_ORDER_REVERSE, /* r */
- SORT_SIZE, /* S */
- SORT_VERSION, /* v */
- SORT_EXT, /* v */
-#endif
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
- LIST_FULLTIME, /* e */
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- TIME_CHANGE | SORT_CTIME, /* c */
-#else
- TIME_CHANGE, /* c */
-#endif
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- TIME_ACCESS | SORT_ATIME, /* u */
-#else
- TIME_ACCESS, /* u */
-#endif
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- SORT_MTIME, /* t */
-#else
- 0, /* t - ignored -- is this correct? */
-#endif
-#endif
-#ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
- FOLLOW_LINKS, /* L */
-#endif
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
-LS_DISP_HR, /* h */
-#endif
-#ifndef CONFIG_SELINUX
- 0, /* k - ingored */
-#else
- LIST_CONTEXT, /* k */
- LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
-#endif
-};
-
-/*----------------------------------------------------------------------*/
-
-extern int ls_main(int argc, char **argv)
+int ls_main(int argc UNUSED_PARAM, char **argv)
{
- struct dnode **dnf, **dnd;
- int dnfiles, dndirs;
- struct dnode *dn, *cur, **dnp;
- int i, nfiles;
- int opt;
- int oi, ac;
- char **av;
-#ifdef CONFIG_SELINUX
- is_flask_enabled_flag = is_flask_enabled();
+ struct dnode **dnd;
+ struct dnode **dnf;
+ struct dnode **dnp;
+ struct dnode *dn;
+ struct dnode *cur;
+ unsigned opt;
+ int nfiles;
+ int dnfiles;
+ int dndirs;
+ int i;
+#if ENABLE_FEATURE_LS_COLOR
+ /* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
+ /* coreutils 6.10:
+ * # ls --color=BOGUS
+ * ls: invalid argument 'BOGUS' for '--color'
+ * Valid arguments are:
+ * 'always', 'yes', 'force'
+ * 'never', 'no', 'none'
+ * 'auto', 'tty', 'if-tty'
+ * (and substrings: "--color=alwa" work too)
+ */
+ static const char ls_longopts[] ALIGN1 =
+ "color\0" Optional_argument "\xff"; /* no short equivalent */
+ static const char color_str[] ALIGN1 =
+ "always\0""yes\0""force\0"
+ "auto\0""tty\0""if-tty\0";
+ /* need to initialize since --color has _an optional_ argument */
+ const char *color_opt = color_str; /* "always" */
#endif
-#ifdef CONFIG_FEATURE_AUTOWIDTH
- struct winsize win = { 0, 0, 0, 0 };
-#endif
+ INIT_G();
- all_fmt = LIST_SHORT | DISP_NORMAL | STYLE_AUTO
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
- | TIME_MOD
-#endif
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- | SORT_NAME | SORT_ORDER_FORWARD
-#endif
- ;
-#ifdef CONFIG_FEATURE_AUTOWIDTH
- ioctl(fileno(stdout), TIOCGWINSZ, &win);
- if (win.ws_col > 0)
- terminal_width = win.ws_col - 1;
-#endif
- nfiles = 0;
+ all_fmt = LIST_SHORT |
+ (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
-#ifdef CONFIG_FEATURE_LS_COLOR
- if (isatty(fileno(stdout)))
- show_color = 1;
+#if ENABLE_FEATURE_AUTOWIDTH
+ /* Obtain the terminal width */
+ get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL);
+ /* Go one less... */
+ terminal_width--;
#endif
/* process options */
- while ((opt = getopt(argc, argv, ls_opts)) > 0) {
-#ifdef CONFIG_FEATURE_AUTOWIDTH
- if (opt == 'T') {
- tabstops = atoi(optarg);
- continue;
- }
- if (opt == 'w') {
- terminal_width = atoi(optarg);
- continue;
- }
- if (opt == ':') {
- goto print_usage_message;
- }
+ USE_FEATURE_LS_COLOR(applet_long_options = ls_longopts;)
+#if ENABLE_FEATURE_AUTOWIDTH
+ opt_complementary = "T+:w+"; /* -T N, -w N */
+ opt = getopt32(argv, ls_options, &tabstops, &terminal_width
+ USE_FEATURE_LS_COLOR(, &color_opt));
+#else
+ opt = getopt32(argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
#endif
- {
- unsigned int flags;
- const char *p = strchr(ls_opts, opt);
- if (!p) { /* shouldn't be necessary */
- goto print_usage_message;
- }
- flags = opt_flags[(int)(p - ls_opts)];
- if (flags & LIST_MASK_TRIGGER) {
+ for (i = 0; opt_flags[i] != (1U<<31); i++) {
+ if (opt & (1 << i)) {
+ unsigned flags = opt_flags[i];
+
+ if (flags & LIST_MASK_TRIGGER)
all_fmt &= ~LIST_MASK;
- }
- if (flags & STYLE_MASK_TRIGGER) {
+ if (flags & STYLE_MASK_TRIGGER)
all_fmt &= ~STYLE_MASK;
- }
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- if (flags & SORT_MASK_TRIGGER) {
+ if (flags & SORT_MASK_TRIGGER)
all_fmt &= ~SORT_MASK;
- }
-#endif
- if (flags & DISP_MASK_TRIGGER) {
+ if (flags & DISP_MASK_TRIGGER)
all_fmt &= ~DISP_MASK;
- }
-#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
- if (flags & TIME_MASK_TRIGGER) {
+ if (flags & TIME_MASK)
all_fmt &= ~TIME_MASK;
- }
-#endif
- if (flags & LIST_CONTEXT) {
+ if (flags & LIST_CONTEXT)
all_fmt |= STYLE_SINGLE;
- }
-#ifdef CONFIG_FEATURE_HUMAN_READABLE
- if (opt == 'l') {
- all_fmt &= ~LS_DISP_HR;
- }
-#endif
+ /* huh?? opt cannot be 'l' */
+ //if (LS_DISP_HR && opt == 'l')
+ // all_fmt &= ~LS_DISP_HR;
all_fmt |= flags;
}
}
+#if ENABLE_FEATURE_LS_COLOR
+ /* find color bit value - last position for short getopt */
+ if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) {
+ char *p = getenv("LS_COLORS");
+ /* LS_COLORS is unset, or (not empty && not "none") ? */
+ if (!p || (p[0] && strcmp(p, "none") != 0))
+ show_color = 1;
+ }
+ if (opt & OPT_color) {
+ if (color_opt[0] == 'n')
+ show_color = 0;
+ else switch (index_in_substrings(color_str, color_opt)) {
+ case 3:
+ case 4:
+ case 5:
+ if (isatty(STDOUT_FILENO)) {
+ case 0:
+ case 1:
+ case 2:
+ show_color = 1;
+ }
+ }
+ }
+#endif
/* sort out which command line options take precedence */
-#ifdef CONFIG_FEATURE_LS_RECURSIVE
- if (all_fmt & DISP_NOLIST)
+ if (ENABLE_FEATURE_LS_RECURSIVE && (all_fmt & DISP_NOLIST))
all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
-#endif
-#if defined (CONFIG_FEATURE_LS_TIMESTAMPS) && defined (CONFIG_FEATURE_LS_SORTFILES)
- if (all_fmt & TIME_CHANGE)
- all_fmt = (all_fmt & ~SORT_MASK) | SORT_CTIME;
- if (all_fmt & TIME_ACCESS)
- all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME;
-#endif
+ if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) {
+ if (all_fmt & TIME_CHANGE)
+ all_fmt = (all_fmt & ~SORT_MASK) | SORT_CTIME;
+ if (all_fmt & TIME_ACCESS)
+ all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME;
+ }
if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */
all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC);
-#ifdef CONFIG_FEATURE_LS_USERNAME
- if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
- all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
-#endif
-
+ if (ENABLE_FEATURE_LS_USERNAME)
+ if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
+ all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
+
/* choose a display format */
- if ((all_fmt & STYLE_MASK) == STYLE_AUTO)
-#if STYLE_AUTO != 0
- all_fmt = (all_fmt & ~STYLE_MASK)
- | (isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE);
-#else
- all_fmt |= (isatty(fileno(stdout)) ? STYLE_COLUMNS : STYLE_SINGLE);
-#endif
+ if (!(all_fmt & STYLE_MASK))
+ all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE);
- /*
- * when there are no cmd line args we have to supply a default "." arg.
- * we will create a second argv array, "av" that will hold either
- * our created "." arg, or the real cmd line args. The av array
- * just holds the pointers- we don't move the date the pointers
- * point to.
- */
- ac = argc - optind; /* how many cmd line args are left */
- if (ac < 1) {
- av = (char **) xcalloc((size_t) 1, (size_t) (sizeof(char *)));
- av[0] = bb_xstrdup(".");
- ac = 1;
- } else {
- av = (char **) xcalloc((size_t) ac, (size_t) (sizeof(char *)));
- for (oi = 0; oi < ac; oi++) {
- av[oi] = argv[optind++]; /* copy pointer to real cmd line arg */
- }
- }
+ argv += optind;
+ if (!argv[0])
+ *--argv = (char*)".";
- /* now, everything is in the av array */
- if (ac > 1)
- all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
+ if (argv[1])
+ all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
- /* stuff the command line file names into an dnode array */
+ /* stuff the command line file names into a dnode array */
dn = NULL;
- for (oi = 0; oi < ac; oi++) {
- char *fullname = bb_xstrdup(av[oi]);
-
- cur = my_stat(fullname, fullname);
+ nfiles = 0;
+ do {
+ /* NB: follow links on command line unless -l or -s */
+ cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS)));
+ argv++;
if (!cur)
continue;
+ cur->allocated = 0;
cur->next = dn;
dn = cur;
nfiles++;
- }
+ } while (*argv);
/* now that we know how many files there are
- ** allocate memory for an array to hold dnode pointers
+ * allocate memory for an array to hold dnode pointers
*/
dnp = dnalloc(nfiles);
for (i = 0, cur = dn; i < nfiles; i++) {
@@ -1065,11 +1049,8 @@ extern int ls_main(int argc, char **argv)
cur = cur->next;
}
-
if (all_fmt & DISP_NOLIST) {
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- shellsort(dnp, nfiles);
-#endif
+ dnsort(dnp, nfiles);
if (nfiles > 0)
showfiles(dnp, nfiles);
} else {
@@ -1078,20 +1059,19 @@ extern int ls_main(int argc, char **argv)
dndirs = countdirs(dnp, nfiles);
dnfiles = nfiles - dndirs;
if (dnfiles > 0) {
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- shellsort(dnf, dnfiles);
-#endif
+ dnsort(dnf, dnfiles);
showfiles(dnf, dnfiles);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(dnf);
}
if (dndirs > 0) {
-#ifdef CONFIG_FEATURE_LS_SORTFILES
- shellsort(dnd, dndirs);
-#endif
- showdirs(dnd, dndirs);
+ dnsort(dnd, dndirs);
+ showdirs(dnd, dndirs, dnfiles == 0);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(dnd);
}
}
- return (status);
-
- print_usage_message:
- bb_show_usage();
+ if (ENABLE_FEATURE_CLEAN_UP)
+ dfree(dnp, nfiles);
+ return exit_code;
}
diff --git a/release/src/router/busybox/coreutils/md5_sha1_sum.c b/release/src/router/busybox/coreutils/md5_sha1_sum.c
new file mode 100644
index 00000000..a988b9cb
--- /dev/null
+++ b/release/src/router/busybox/coreutils/md5_sha1_sum.c
@@ -0,0 +1,192 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Glenn L. McGrath
+ * Copyright (C) 2003-2004 Erik Andersen
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+typedef enum {
+ /* 4th letter of applet_name is... */
+ HASH_MD5 = 's', /* "md5>s<um" */
+ HASH_SHA1 = '1',
+ HASH_SHA256 = '2',
+ HASH_SHA512 = '5',
+} hash_algo_t;
+
+#define FLAG_SILENT 1
+#define FLAG_CHECK 2
+#define FLAG_WARN 4
+
+/* This might be useful elsewhere */
+static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
+ unsigned hash_length)
+{
+ /* xzalloc zero-terminates */
+ char *hex_value = xzalloc((hash_length * 2) + 1);
+ bin2hex(hex_value, (char*)hash_value, hash_length);
+ return (unsigned char *)hex_value;
+}
+
+static uint8_t *hash_file(const char *filename /*, hash_algo_t hash_algo*/)
+{
+ int src_fd, hash_len, count;
+ union _ctx_ {
+ sha512_ctx_t sha512;
+ sha256_ctx_t sha256;
+ sha1_ctx_t sha1;
+ md5_ctx_t md5;
+ } context;
+ uint8_t *hash_value = NULL;
+ RESERVE_CONFIG_UBUFFER(in_buf, 4096);
+ void FAST_FUNC (*update)(const void*, size_t, void*);
+ void FAST_FUNC (*final)(void*, void*);
+ hash_algo_t hash_algo = applet_name[3];
+
+ src_fd = open_or_warn_stdin(filename);
+ if (src_fd < 0) {
+ return NULL;
+ }
+
+ /* figure specific hash algorithims */
+ if (ENABLE_MD5SUM && hash_algo == HASH_MD5) {
+ md5_begin(&context.md5);
+ update = (void*)md5_hash;
+ final = (void*)md5_end;
+ hash_len = 16;
+ } else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) {
+ sha1_begin(&context.sha1);
+ update = (void*)sha1_hash;
+ final = (void*)sha1_end;
+ hash_len = 20;
+ } else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) {
+ sha256_begin(&context.sha256);
+ update = (void*)sha256_hash;
+ final = (void*)sha256_end;
+ hash_len = 32;
+ } else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) {
+ sha512_begin(&context.sha512);
+ update = (void*)sha512_hash;
+ final = (void*)sha512_end;
+ hash_len = 64;
+ } else {
+ bb_error_msg_and_die("algorithm not supported");
+ }
+
+ while (0 < (count = safe_read(src_fd, in_buf, 4096))) {
+ update(in_buf, count, &context);
+ }
+
+ if (count == 0) {
+ final(in_buf, &context);
+ hash_value = hash_bin_to_hex(in_buf, hash_len);
+ }
+
+ RELEASE_CONFIG_BUFFER(in_buf);
+
+ if (src_fd != STDIN_FILENO) {
+ close(src_fd);
+ }
+
+ return hash_value;
+}
+
+int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
+{
+ int return_value = EXIT_SUCCESS;
+ uint8_t *hash_value;
+ unsigned flags;
+ /*hash_algo_t hash_algo = applet_name[3];*/
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK)
+ flags = getopt32(argv, "scw");
+ else optind = 1;
+ argv += optind;
+ //argc -= optind;
+ if (!*argv)
+ *--argv = (char*)"-";
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) {
+ if (flags & FLAG_SILENT) {
+ bb_error_msg_and_die
+ ("-%c is meaningful only when verifying checksums", 's');
+ } else if (flags & FLAG_WARN) {
+ bb_error_msg_and_die
+ ("-%c is meaningful only when verifying checksums", 'w');
+ }
+ }
+
+ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) {
+ FILE *pre_computed_stream;
+ int count_total = 0;
+ int count_failed = 0;
+ char *line;
+
+ if (argv[1]) {
+ bb_error_msg_and_die
+ ("only one argument may be specified when using -c");
+ }
+
+ pre_computed_stream = xfopen_stdin(argv[0]);
+
+ while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) {
+ char *filename_ptr;
+
+ count_total++;
+ filename_ptr = strstr(line, " ");
+ /* handle format for binary checksums */
+ if (filename_ptr == NULL) {
+ filename_ptr = strstr(line, " *");
+ }
+ if (filename_ptr == NULL) {
+ if (flags & FLAG_WARN) {
+ bb_error_msg("invalid format");
+ }
+ count_failed++;
+ return_value = EXIT_FAILURE;
+ free(line);
+ continue;
+ }
+ *filename_ptr = '\0';
+ filename_ptr += 2;
+
+ hash_value = hash_file(filename_ptr /*, hash_algo*/);
+
+ if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
+ if (!(flags & FLAG_SILENT))
+ printf("%s: OK\n", filename_ptr);
+ } else {
+ if (!(flags & FLAG_SILENT))
+ printf("%s: FAILED\n", filename_ptr);
+ count_failed++;
+ return_value = EXIT_FAILURE;
+ }
+ /* possible free(NULL) */
+ free(hash_value);
+ free(line);
+ }
+ if (count_failed && !(flags & FLAG_SILENT)) {
+ bb_error_msg("WARNING: %d of %d computed checksums did NOT match",
+ count_failed, count_total);
+ }
+ /*
+ if (fclose_if_not_stdin(pre_computed_stream) == EOF) {
+ bb_perror_msg_and_die("cannot close file %s", file_ptr);
+ }
+ */
+ } else {
+ do {
+ hash_value = hash_file(*argv/*, hash_algo*/);
+ if (hash_value == NULL) {
+ return_value = EXIT_FAILURE;
+ } else {
+ printf("%s %s\n", hash_value, *argv);
+ free(hash_value);
+ }
+ } while (*++argv);
+ }
+ return return_value;
+}
diff --git a/release/src/router/busybox/coreutils/md5sum.c b/release/src/router/busybox/coreutils/md5sum.c
deleted file mode 100644
index c0294f4c..00000000
--- a/release/src/router/busybox/coreutils/md5sum.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/* md5sum.c - Compute MD5 checksum of files or strings according to the
- * definition of MD5 in RFC 1321 from April 1992.
- * Copyright (C) 1995-1999 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu> */
-/* Hacked to work with BusyBox by Alfred M. Szmidt <ams@trillian.itslinux.org> */
-
-/*
- * June 29, 2001 Manuel Novoa III
- *
- * Added MD5SUM_SIZE_VS_SPEED configuration option.
- *
- * Current valid values, with data from my system for comparison, are:
- * (using uClibc and running on linux-2.4.4.tar.bz2)
- * user times (sec) text size (386)
- * 0 (fastest) 1.1 6144
- * 1 1.4 5392
- * 2 3.0 5088
- * 3 (smallest) 5.1 4912
- */
-
-#define MD5SUM_SIZE_VS_SPEED 2
-
-/**********************************************************************/
-
-#include <stdio.h>
-#include <errno.h>
-#include <ctype.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-#include <endian.h>
-#include <sys/types.h>
-#if defined HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include "busybox.h"
-
-/* For some silly reason, this file uses backwards TRUE and FALSE conventions */
-#undef TRUE
-#undef FALSE
-#define FALSE ((int) 1)
-#define TRUE ((int) 0)
-
-//----------------------------------------------------------------------------
-//--------md5.c
-//----------------------------------------------------------------------------
-
-/* md5.c - Functions to compute MD5 message digest of files or memory blocks
- * according to the definition of MD5 in RFC 1321 from April 1992.
- */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
-
-//----------------------------------------------------------------------------
-//--------md5.h
-//----------------------------------------------------------------------------
-
-/* md5.h - Declaration of functions and data types used for MD5 sum
- computing library functions. */
-
-typedef u_int32_t md5_uint32;
-
-/* Structure to save state of computation between the single steps. */
-struct md5_ctx {
- md5_uint32 A;
- md5_uint32 B;
- md5_uint32 C;
- md5_uint32 D;
-
- md5_uint32 total[2];
- md5_uint32 buflen;
- char buffer[128];
-};
-
-/*
- * The following three functions are build up the low level used in
- * the functions `md5_stream' and `md5_buffer'.
- */
-
-/* Initialize structure containing state of computation.
- (RFC 1321, 3.3: Step 3) */
-static void md5_init_ctx __P((struct md5_ctx * ctx));
-
-/* Starting with the result of former calls of this function (or the
- initialization function update the context for the next LEN bytes
- starting at BUFFER.
- It is necessary that LEN is a multiple of 64!!! */
-static void md5_process_block __P((const void *buffer, size_t len,
- struct md5_ctx * ctx));
-
-/* Starting with the result of former calls of this function (or the
- initialization function update the context for the next LEN bytes
- starting at BUFFER.
- It is NOT required that LEN is a multiple of 64. */
-static void md5_process_bytes __P((const void *buffer, size_t len,
- struct md5_ctx * ctx));
-
-/* Process the remaining bytes in the buffer and put result from CTX
- in first 16 bytes following RESBUF. The result is always in little
- endian byte order, so that a byte-wise output yields to the wanted
- ASCII representation of the message digest.
-
- IMPORTANT: On some systems it is required that RESBUF is correctly
- aligned for a 32 bits value. */
-static void *md5_finish_ctx __P((struct md5_ctx * ctx, void *resbuf));
-
-
-
-
-/* Compute MD5 message digest for bytes read from STREAM. The
- resulting message digest number will be written into the 16 bytes
- beginning at RESBLOCK. */
-static int md5_stream __P((FILE * stream, void *resblock));
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- result is always in little endian byte order, so that a byte-wise
- output yields to the wanted ASCII representation of the message
- digest. */
-static void *md5_buffer __P((const char *buffer, size_t len, void *resblock));
-
-//----------------------------------------------------------------------------
-//--------end of md5.h
-//----------------------------------------------------------------------------
-
-/* Handle endian-ness */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define SWAP(n) (n)
-#else
-#define SWAP(n) ((n << 24) | ((n&65280)<<8) | ((n&16711680)>>8) | (n>>24))
-#endif
-
-
-
-#if MD5SUM_SIZE_VS_SPEED == 0
-/* This array contains the bytes used to pad the buffer to the next
- 64-byte boundary. (RFC 1321, 3.1: Step 1) */
-static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
-#endif
-
-/* Initialize structure containing state of computation.
- (RFC 1321, 3.3: Step 3) */
-void md5_init_ctx(struct md5_ctx *ctx)
-{
- ctx->A = 0x67452301;
- ctx->B = 0xefcdab89;
- ctx->C = 0x98badcfe;
- ctx->D = 0x10325476;
-
- ctx->total[0] = ctx->total[1] = 0;
- ctx->buflen = 0;
-}
-
-/* Process the remaining bytes in the internal buffer and the usual
- prolog according to the standard and write the result to RESBUF.
-
- IMPORTANT: On some systems it is required that RESBUF is correctly
- aligned for a 32 bits value. */
-static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
-{
- /* Take yet unprocessed bytes into account. */
- md5_uint32 bytes = ctx->buflen;
- size_t pad;
-
- /* Now count remaining bytes. */
- ctx->total[0] += bytes;
- if (ctx->total[0] < bytes)
- ++ctx->total[1];
-
- pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
-#if MD5SUM_SIZE_VS_SPEED > 0
- memset(&ctx->buffer[bytes], 0, pad);
- ctx->buffer[bytes] = 0x80;
-#else
- memcpy(&ctx->buffer[bytes], fillbuf, pad);
-#endif
-
- /* Put the 64-bit file length in *bits* at the end of the buffer. */
- *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP(ctx->total[0] << 3);
- *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] =
- SWAP(((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
-
- /* Process last bytes. */
- md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
-
-/* Put result from CTX in first 16 bytes following RESBUF. The result is
- always in little endian byte order, so that a byte-wise output yields
- to the wanted ASCII representation of the message digest.
-
- IMPORTANT: On some systems it is required that RESBUF is correctly
- aligned for a 32 bits value. */
- ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
- ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
- ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
- ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
-
- return resbuf;
-}
-
-/* Compute MD5 message digest for bytes read from STREAM. The
- resulting message digest number will be written into the 16 bytes
- beginning at RESBLOCK. */
-static int md5_stream(FILE * stream, void *resblock)
-{
- /* Important: BLOCKSIZE must be a multiple of 64. */
- static const int BLOCKSIZE = 4096;
- struct md5_ctx ctx;
- char buffer[BLOCKSIZE + 72];
- size_t sum;
-
- /* Initialize the computation context. */
- md5_init_ctx(&ctx);
-
- /* Iterate over full file contents. */
- while (1) {
- /* We read the file in blocks of BLOCKSIZE bytes. One call of the
- computation function processes the whole buffer so that with the
- next round of the loop another block can be read. */
- size_t n;
-
- sum = 0;
-
- /* Read block. Take care for partial reads. */
- do {
- n = fread(buffer + sum, 1, BLOCKSIZE - sum, stream);
-
- sum += n;
- }
- while (sum < BLOCKSIZE && n != 0);
- if (n == 0 && ferror(stream))
- return 1;
-
- /* If end of file is reached, end the loop. */
- if (n == 0)
- break;
-
- /* Process buffer with BLOCKSIZE bytes. Note that
- BLOCKSIZE % 64 == 0
- */
- md5_process_block(buffer, BLOCKSIZE, &ctx);
- }
-
- /* Add the last bytes if necessary. */
- if (sum > 0)
- md5_process_bytes(buffer, sum, &ctx);
-
- /* Construct result in desired memory. */
- md5_finish_ctx(&ctx, resblock);
- return 0;
-}
-
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- result is always in little endian byte order, so that a byte-wise
- output yields to the wanted ASCII representation of the message
- digest. */
-static void *md5_buffer(const char *buffer, size_t len, void *resblock)
-{
- struct md5_ctx ctx;
-
- /* Initialize the computation context. */
- md5_init_ctx(&ctx);
-
- /* Process whole buffer but last len % 64 bytes. */
- md5_process_bytes(buffer, len, &ctx);
-
- /* Put result in desired memory area. */
- return md5_finish_ctx(&ctx, resblock);
-}
-
-static void md5_process_bytes(const void *buffer, size_t len,
- struct md5_ctx *ctx)
-{
- /* When we already have some bits in our internal buffer concatenate
- both inputs first. */
- if (ctx->buflen != 0) {
- size_t left_over = ctx->buflen;
- size_t add = 128 - left_over > len ? len : 128 - left_over;
-
- memcpy(&ctx->buffer[left_over], buffer, add);
- ctx->buflen += add;
-
- if (left_over + add > 64) {
- md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
- /* The regions in the following copy operation cannot overlap. */
- memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
- (left_over + add) & 63);
- ctx->buflen = (left_over + add) & 63;
- }
-
- buffer = (const char *) buffer + add;
- len -= add;
- }
-
- /* Process available complete blocks. */
- if (len > 64) {
- md5_process_block(buffer, len & ~63, ctx);
- buffer = (const char *) buffer + (len & ~63);
- len &= 63;
- }
-
- /* Move remaining bytes in internal buffer. */
- if (len > 0) {
- memcpy(ctx->buffer, buffer, len);
- ctx->buflen = len;
- }
-}
-
-/* These are the four functions used in the four steps of the MD5 algorithm
- and defined in the RFC 1321. The first function is a little bit optimized
- (as found in Colin Plumbs public domain implementation). */
-/* #define FF(b, c, d) ((b & c) | (~b & d)) */
-#define FF(b, c, d) (d ^ (b & (c ^ d)))
-#define FG(b, c, d) FF (d, b, c)
-#define FH(b, c, d) (b ^ c ^ d)
-#define FI(b, c, d) (c ^ (b | ~d))
-
-/* Process LEN bytes of BUFFER, accumulating context into CTX.
- It is assumed that LEN % 64 == 0. */
-static void md5_process_block(const void *buffer, size_t len,
- struct md5_ctx *ctx)
-{
- md5_uint32 correct_words[16];
- const md5_uint32 *words = buffer;
- size_t nwords = len / sizeof(md5_uint32);
- const md5_uint32 *endp = words + nwords;
-
-#if MD5SUM_SIZE_VS_SPEED > 0
- static const md5_uint32 C_array[] = {
- /* round 1 */
- 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
- 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
- 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
- 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
- /* round 2 */
- 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
- 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
- 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
- 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
- /* round 3 */
- 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
- 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
- 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
- 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
- /* round 4 */
- 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
- 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
- 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
- 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
- };
-
- static const char P_array[] = {
-#if MD5SUM_SIZE_VS_SPEED > 1
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
-#endif
- 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
- 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
- 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
- };
-
-#if MD5SUM_SIZE_VS_SPEED > 1
- static const char S_array[] = {
- 7, 12, 17, 22,
- 5, 9, 14, 20,
- 4, 11, 16, 23,
- 6, 10, 15, 21
- };
-#endif
-#endif
-
- md5_uint32 A = ctx->A;
- md5_uint32 B = ctx->B;
- md5_uint32 C = ctx->C;
- md5_uint32 D = ctx->D;
-
- /* First increment the byte count. RFC 1321 specifies the possible
- length of the file up to 2^64 bits. Here we only compute the
- number of bytes. Do a double word increment. */
- ctx->total[0] += len;
- if (ctx->total[0] < len)
- ++ctx->total[1];
-
- /* Process all bytes in the buffer with 64 bytes in each round of
- the loop. */
- while (words < endp) {
- md5_uint32 *cwp = correct_words;
- md5_uint32 A_save = A;
- md5_uint32 B_save = B;
- md5_uint32 C_save = C;
- md5_uint32 D_save = D;
-
-#if MD5SUM_SIZE_VS_SPEED > 1
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
- const md5_uint32 *pc;
- const char *pp;
- const char *ps;
- int i;
- md5_uint32 temp;
-
- for (i = 0; i < 16; i++) {
- cwp[i] = SWAP(words[i]);
- }
- words += 16;
-
-#if MD5SUM_SIZE_VS_SPEED > 2
- pc = C_array;
- pp = P_array;
- ps = S_array - 4;
-
- for (i = 0; i < 64; i++) {
- if ((i & 0x0f) == 0)
- ps += 4;
- temp = A;
- switch (i >> 4) {
- case 0:
- temp += FF(B, C, D);
- break;
- case 1:
- temp += FG(B, C, D);
- break;
- case 2:
- temp += FH(B, C, D);
- break;
- case 3:
- temp += FI(B, C, D);
- }
- temp += cwp[(int) (*pp++)] + *pc++;
- CYCLIC(temp, ps[i & 3]);
- temp += B;
- A = D;
- D = C;
- C = B;
- B = temp;
- }
-#else
- pc = C_array;
- pp = P_array;
- ps = S_array;
-
- for (i = 0; i < 16; i++) {
- temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
- CYCLIC(temp, ps[i & 3]);
- temp += B;
- A = D;
- D = C;
- C = B;
- B = temp;
- }
-
- ps += 4;
- for (i = 0; i < 16; i++) {
- temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
- CYCLIC(temp, ps[i & 3]);
- temp += B;
- A = D;
- D = C;
- C = B;
- B = temp;
- }
- ps += 4;
- for (i = 0; i < 16; i++) {
- temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
- CYCLIC(temp, ps[i & 3]);
- temp += B;
- A = D;
- D = C;
- C = B;
- B = temp;
- }
- ps += 4;
- for (i = 0; i < 16; i++) {
- temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
- CYCLIC(temp, ps[i & 3]);
- temp += B;
- A = D;
- D = C;
- C = B;
- B = temp;
- }
-
-#endif
-#else
- /* First round: using the given function, the context and a constant
- the next context is computed. Because the algorithms processing
- unit is a 32-bit word and it is determined to work on words in
- little endian byte order we perhaps have to change the byte order
- before the computation. To reduce the work for the next steps
- we store the swapped words in the array CORRECT_WORDS. */
-
-#define OP(a, b, c, d, s, T) \
- do \
- { \
- a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
- ++words; \
- CYCLIC (a, s); \
- a += b; \
- } \
- while (0)
-
- /* It is unfortunate that C does not provide an operator for
- cyclic rotation. Hope the C compiler is smart enough. */
- /* gcc 2.95.4 seems to be --aaronl */
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-
- /* Before we start, one word to the strange constants.
- They are defined in RFC 1321 as
-
- T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
- */
-
-#if MD5SUM_SIZE_VS_SPEED == 1
- const md5_uint32 *pc;
- const char *pp;
- int i;
-#endif
-
- /* Round 1. */
-#if MD5SUM_SIZE_VS_SPEED == 1
- pc = C_array;
- for (i = 0; i < 4; i++) {
- OP(A, B, C, D, 7, *pc++);
- OP(D, A, B, C, 12, *pc++);
- OP(C, D, A, B, 17, *pc++);
- OP(B, C, D, A, 22, *pc++);
- }
-#else
- OP(A, B, C, D, 7, 0xd76aa478);
- OP(D, A, B, C, 12, 0xe8c7b756);
- OP(C, D, A, B, 17, 0x242070db);
- OP(B, C, D, A, 22, 0xc1bdceee);
- OP(A, B, C, D, 7, 0xf57c0faf);
- OP(D, A, B, C, 12, 0x4787c62a);
- OP(C, D, A, B, 17, 0xa8304613);
- OP(B, C, D, A, 22, 0xfd469501);
- OP(A, B, C, D, 7, 0x698098d8);
- OP(D, A, B, C, 12, 0x8b44f7af);
- OP(C, D, A, B, 17, 0xffff5bb1);
- OP(B, C, D, A, 22, 0x895cd7be);
- OP(A, B, C, D, 7, 0x6b901122);
- OP(D, A, B, C, 12, 0xfd987193);
- OP(C, D, A, B, 17, 0xa679438e);
- OP(B, C, D, A, 22, 0x49b40821);
-#endif
-
- /* For the second to fourth round we have the possibly swapped words
- in CORRECT_WORDS. Redefine the macro to take an additional first
- argument specifying the function to use. */
-#undef OP
-#define OP(f, a, b, c, d, k, s, T) \
- do \
- { \
- a += f (b, c, d) + correct_words[k] + T; \
- CYCLIC (a, s); \
- a += b; \
- } \
- while (0)
-
- /* Round 2. */
-#if MD5SUM_SIZE_VS_SPEED == 1
- pp = P_array;
- for (i = 0; i < 4; i++) {
- OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
- OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
- OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
- OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
- }
-#else
- OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
- OP(FG, D, A, B, C, 6, 9, 0xc040b340);
- OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
- OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
- OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
- OP(FG, D, A, B, C, 10, 9, 0x02441453);
- OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
- OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
- OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
- OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
- OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
- OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
- OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
- OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
- OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
- OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
-#endif
-
- /* Round 3. */
-#if MD5SUM_SIZE_VS_SPEED == 1
- for (i = 0; i < 4; i++) {
- OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
- OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
- OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
- OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
- }
-#else
- OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
- OP(FH, D, A, B, C, 8, 11, 0x8771f681);
- OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
- OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
- OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
- OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
- OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
- OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
- OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
- OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
- OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
- OP(FH, B, C, D, A, 6, 23, 0x04881d05);
- OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
- OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
- OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
- OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
-#endif
-
- /* Round 4. */
-#if MD5SUM_SIZE_VS_SPEED == 1
- for (i = 0; i < 4; i++) {
- OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
- OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
- OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
- OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
- }
-#else
- OP(FI, A, B, C, D, 0, 6, 0xf4292244);
- OP(FI, D, A, B, C, 7, 10, 0x432aff97);
- OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
- OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
- OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
- OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
- OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
- OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
- OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
- OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
- OP(FI, C, D, A, B, 6, 15, 0xa3014314);
- OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
- OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
- OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
- OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
- OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
-#endif
-#endif
-
- /* Add the starting values of the context. */
- A += A_save;
- B += B_save;
- C += C_save;
- D += D_save;
- }
-
- /* Put checksum in context given as argument. */
- ctx->A = A;
- ctx->B = B;
- ctx->C = C;
- ctx->D = D;
-}
-
-//----------------------------------------------------------------------------
-//--------end of md5.c
-//----------------------------------------------------------------------------
-
-#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
-#define ISXDIGIT(c) (isxdigit (c))
-
-/* The minimum length of a valid digest line in a file produced
- by `md5sum FILE' and read by `md5sum -c'. This length does
- not include any newline character at the end of a line. */
-static const int MIN_DIGEST_LINE_LENGTH = 35; /* 32 - message digest length
- 2 - blank and binary indicator
- 1 - minimum filename length */
-
-static int have_read_stdin; /* Nonzero if any of the files read were
- the standard input. */
-
-static int status_only = 0; /* With -c, don't generate any output.
- The exit code indicates success or failure */
-static int warn = 0; /* With -w, print a message to standard error warning
- about each improperly formatted MD5 checksum line */
-
-static int split_3(char *s, size_t s_len, unsigned char **u, char **w)
-{
- size_t i = 0;
- int escaped_filename = 0;
-
- while (ISWHITE(s[i]))
- ++i;
-
- /* The line must have at least 35 (36 if the first is a backslash)
- more characters to contain correct message digest information.
- Ignore this line if it is too short. */
- if (!(s_len - i >= MIN_DIGEST_LINE_LENGTH
- || (s[i] == '\\' && s_len - i >= 1 + MIN_DIGEST_LINE_LENGTH)))
- return FALSE;
-
- if (s[i] == '\\') {
- ++i;
- escaped_filename = 1;
- }
- *u = (unsigned char *) &s[i];
-
- /* The first field has to be the 32-character hexadecimal
- representation of the message digest. If it is not followed
- immediately by a white space it's an error. */
- i += 32;
- if (!ISWHITE(s[i]))
- return FALSE;
-
- s[i++] = '\0';
-
- if (s[i] != ' ' && s[i] != '*')
- return FALSE;
-
- /* All characters between the type indicator and end of line are
- significant -- that includes leading and trailing white space. */
- *w = &s[++i];
-
- if (escaped_filename) {
- /* Translate each `\n' string in the file name to a NEWLINE,
- and each `\\' string to a backslash. */
-
- char *dst = &s[i];
-
- while (i < s_len) {
- switch (s[i]) {
- case '\\':
- if (i == s_len - 1) {
- /* A valid line does not end with a backslash. */
- return FALSE;
- }
- ++i;
- switch (s[i++]) {
- case 'n':
- *dst++ = '\n';
- break;
- case '\\':
- *dst++ = '\\';
- break;
- default:
- /* Only `\' or `n' may follow a backslash. */
- return FALSE;
- }
- break;
-
- case '\0':
- /* The file name may not contain a NUL. */
- return FALSE;
- break;
-
- default:
- *dst++ = s[i++];
- break;
- }
- }
- *dst = '\0';
- }
- return TRUE;
-}
-
-static inline int hex_digits(unsigned char const *s)
-{
- while (*s) {
- if (!ISXDIGIT(*s))
- return TRUE;
- ++s;
- }
- return FALSE;
-}
-
-/* An interface to md5_stream. Operate on FILENAME (it may be "-") and
- put the result in *MD5_RESULT. Return non-zero upon failure, zero
- to indicate success. */
-static int md5_file(const char *filename, unsigned char *md5_result)
-{
- FILE *fp;
-
- if (filename[0] == '-' && filename[1] == '\0') {
- have_read_stdin = 1;
- fp = stdin;
- } else {
- fp = bb_wfopen(filename, "r");
- if (fp == NULL)
- return FALSE;
- }
-
- if (md5_stream(fp, md5_result)) {
- bb_perror_msg("%s", filename);
-
- if (fp != stdin)
- fclose(fp);
- return FALSE;
- }
-
- if (fp != stdin && fclose(fp) == EOF) {
- bb_perror_msg("%s", filename);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static int md5_check(const char *checkfile_name)
-{
- FILE *checkfile_stream;
- int n_properly_formated_lines = 0;
- int n_mismatched_checksums = 0;
- int n_open_or_read_failures = 0;
- unsigned char md5buffer[16];
- size_t line_number;
- char line[BUFSIZ];
-
- if (checkfile_name[0] == '-' && checkfile_name[1] == '\0') {
- have_read_stdin = 1;
- checkfile_stream = stdin;
- } else {
- checkfile_stream = bb_wfopen(checkfile_name, "r");
- if (checkfile_stream == NULL)
- return FALSE;
- }
-
- line_number = 0;
-
- do {
- char *filename;
- unsigned char *md5num;
- int line_length;
-
- ++line_number;
-
- fgets(line, BUFSIZ - 1, checkfile_stream);
- line_length = strlen(line);
-
- if (line_length <= 0 || line == NULL)
- break;
-
- /* Ignore comment lines, which begin with a '#' character. */
- if (line[0] == '#')
- continue;
-
- /* Remove any trailing newline. */
- if (line[line_length - 1] == '\n')
- line[--line_length] = '\0';
-
- if (split_3(line, line_length, &md5num, &filename)
- || !hex_digits(md5num)) {
- if (warn) {
- bb_error_msg
- ("%s: %lu: improperly formatted MD5 checksum line",
- checkfile_name, (unsigned long) line_number);
- }
- } else {
- static const char bin2hex[] = {
- '0', '1', '2', '3',
- '4', '5', '6', '7',
- '8', '9', 'a', 'b',
- 'c', 'd', 'e', 'f'
- };
-
- ++n_properly_formated_lines;
-
- if (md5_file(filename, md5buffer)) {
- ++n_open_or_read_failures;
- if (!status_only) {
- printf("%s: FAILED open or read\n", filename);
- fflush(stdout);
- }
- } else {
- size_t cnt;
-
- /* Compare generated binary number with text representation
- in check file. Ignore case of hex digits. */
- for (cnt = 0; cnt < 16; ++cnt) {
- if (tolower(md5num[2 * cnt])
- != bin2hex[md5buffer[cnt] >> 4]
- || (tolower(md5num[2 * cnt + 1])
- != (bin2hex[md5buffer[cnt] & 0xf])))
- break;
- }
- if (cnt != 16)
- ++n_mismatched_checksums;
-
- if (!status_only) {
- printf("%s: %s\n", filename,
- (cnt != 16 ? "FAILED" : "OK"));
- fflush(stdout);
- }
- }
- }
- }
-
- while (!feof(checkfile_stream) && !ferror(checkfile_stream));
-
- if (ferror(checkfile_stream)) {
- bb_error_msg("%s: read error", checkfile_name);
- return FALSE;
- }
-
- if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) {
- bb_perror_msg("md5sum: %s", checkfile_name);
- return FALSE;
- }
-
- if (n_properly_formated_lines == 0) {
- /* Warn if no tests are found. */
- bb_error_msg("%s: no properly formatted MD5 checksum lines found",
- checkfile_name);
- return FALSE;
- } else {
- if (!status_only) {
- int n_computed_checkums = (n_properly_formated_lines
- - n_open_or_read_failures);
-
- if (n_open_or_read_failures > 0) {
- bb_error_msg
- ("WARNING: %d of %d listed files could not be read",
- n_open_or_read_failures, n_properly_formated_lines);
- return FALSE;
- }
-
- if (n_mismatched_checksums > 0) {
- bb_error_msg
- ("WARNING: %d of %d computed checksums did NOT match",
- n_mismatched_checksums, n_computed_checkums);
- return FALSE;
- }
- }
- }
-
- return ((n_properly_formated_lines > 0 && n_mismatched_checksums == 0
- && n_open_or_read_failures == 0) ? 0 : 1);
-}
-
-int md5sum_main(int argc, char **argv)
-{
- unsigned char md5buffer[16];
- int do_check = 0;
- int opt;
- char **string = NULL;
- size_t n_strings = 0;
- size_t err = 0;
- char file_type_specified = 0;
- char binary = 0;
-
- while ((opt = getopt(argc, argv, "g:bcstw")) != -1) {
- switch (opt) {
- case 'g':{ /* read a string */
- if (string == NULL)
- string = (char **) xmalloc((argc - 1) * sizeof(char *));
-
- string[n_strings++] = optarg;
- break;
- }
-
- case 'b': /* read files in binary mode */
- file_type_specified = 1;
- binary = 1;
- break;
-
- case 'c': /* check MD5 sums against given list */
- do_check = 1;
- break;
-
- case 's': /* don't output anything, status code shows success */
- status_only = 1;
- warn = 0;
- break;
-
- case 't': /* read files in text mode (default) */
- file_type_specified = 1;
- binary = 0;
- break;
-
- case 'w': /* warn about improperly formated MD5 checksum lines */
- status_only = 0;
- warn = 1;
- break;
-
- default:
- bb_show_usage();
- }
- }
-
- if (file_type_specified && do_check) {
- bb_error_msg_and_die
- ("the -b and -t options are meaningless when verifying checksums");
- }
-
- if (n_strings > 0 && do_check) {
- bb_error_msg_and_die("the -g and -c options are mutually exclusive");
- }
-
- if (status_only && !do_check) {
- bb_error_msg_and_die
- ("the -s option is meaningful only when verifying checksums");
- }
-
- if (warn && !do_check) {
- bb_error_msg_and_die
- ("the -w option is meaningful only when verifying checksums");
- }
-
- if (n_strings > 0) {
- size_t i;
-
- if (optind < argc) {
- bb_error_msg_and_die("no files may be specified when using -g");
- }
- for (i = 0; i < n_strings; ++i) {
- size_t cnt;
-
- md5_buffer(string[i], strlen(string[i]), md5buffer);
-
- for (cnt = 0; cnt < 16; ++cnt)
- printf("%02x", md5buffer[cnt]);
-
- printf(" \"%s\"\n", string[i]);
- }
- } else if (do_check) {
- if (optind + 1 < argc) {
- bb_error_msg("only one argument may be specified when using -c");
- }
-
- err = md5_check((optind == argc) ? "-" : argv[optind]);
- } else {
- if (optind == argc)
- argv[argc++] = "-";
-
- for (; optind < argc; ++optind) {
- int fail;
- char *file = argv[optind];
-
- fail = md5_file(file, md5buffer);
- err |= fail;
- if (!fail && file[0] == '-' && file[1] == '\0') {
- size_t i;
-
- for (i = 0; i < 16; ++i)
- printf("%02x", md5buffer[i]);
- putchar('\n');
- } else if (!fail) {
- size_t i;
-
- /* Output a leading backslash if the file name contains
- a newline or backslash. */
- if (strchr(file, '\n') || strchr(file, '\\'))
- putchar('\\');
-
- for (i = 0; i < 16; ++i)
- printf("%02x", md5buffer[i]);
-
- putchar(' ');
- if (binary)
- putchar('*');
- else
- putchar(' ');
-
- /* Translate each NEWLINE byte to the string, "\\n",
- and each backslash to "\\\\". */
- for (i = 0; i < strlen(file); ++i) {
- switch (file[i]) {
- case '\n':
- fputs("\\n", stdout);
- break;
-
- case '\\':
- fputs("\\\\", stdout);
- break;
-
- default:
- putchar(file[i]);
- break;
- }
- }
- putchar('\n');
- }
- }
- }
-
- if (fclose(stdout) == EOF) {
- bb_error_msg_and_die("write error");
- }
-
- if (have_read_stdin && fclose(stdin) == EOF) {
- bb_error_msg_and_die(bb_msg_standard_input);
- }
-
- if (err == 0)
- return EXIT_SUCCESS;
- else
- return EXIT_FAILURE;
-}
diff --git a/release/src/router/busybox/coreutils/mkdir.c b/release/src/router/busybox/coreutils/mkdir.c
index 50364f17..72bd1058 100644
--- a/release/src/router/busybox/coreutils/mkdir.c
+++ b/release/src/router/busybox/coreutils/mkdir.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
@@ -29,35 +16,53 @@
* conjunction with -m.
*/
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-#include "busybox.h"
+/* Nov 28, 2006 Yoshinori Sato <ysato@users.sourceforge.jp>: Add SELinux Support.
+ */
-static const struct option mkdir_long_options[] = {
- { "mode", 1, NULL, 'm' },
- { "parents", 0, NULL, 'p' },
- { 0, 0, 0, 0 }
-};
+#include "libbb.h"
-extern int mkdir_main (int argc, char **argv)
+/* This is a NOFORK applet. Be very careful! */
+
+#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
+static const char mkdir_longopts[] ALIGN1 =
+ "mode\0" Required_argument "m"
+ "parents\0" No_argument "p"
+#if ENABLE_SELINUX
+ "context\0" Required_argument "Z"
+#endif
+ ;
+#endif
+
+int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkdir_main(int argc, char **argv)
{
mode_t mode = (mode_t)(-1);
int status = EXIT_SUCCESS;
int flags = 0;
- unsigned long opt;
+ unsigned opt;
char *smode;
+#if ENABLE_SELINUX
+ security_context_t scontext;
+#endif
- bb_applet_long_options = mkdir_long_options;
- opt = bb_getopt_ulflags(argc, argv, "m:p", &smode);
- if(opt & 1) {
- mode = 0777;
- if (!bb_parse_mode (smode, &mode)) {
- bb_error_msg_and_die ("invalid mode `%s'", smode);
+#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
+ applet_long_options = mkdir_longopts;
+#endif
+ opt = getopt32(argv, "m:p" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+ if (opt & 1) {
+ mode = 0777;
+ if (!bb_parse_mode(smode, &mode)) {
+ bb_error_msg_and_die("invalid mode '%s'", smode);
}
}
- if(opt & 2)
+ if (opt & 2)
flags |= FILEUTILS_RECUR;
+#if ENABLE_SELINUX
+ if (opt & 4) {
+ selinux_or_die();
+ setfscreatecon_or_die(scontext);
+ }
+#endif
if (optind == argc) {
bb_show_usage();
diff --git a/release/src/router/busybox/coreutils/mkfifo.c b/release/src/router/busybox/coreutils/mkfifo.c
index 77e0e6dd..65494609 100644
--- a/release/src/router/busybox/coreutils/mkfifo.c
+++ b/release/src/router/busybox/coreutils/mkfifo.c
@@ -4,45 +4,31 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkfifo.html */
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
+#include "libbb.h"
#include "libcoreutils/coreutils.h"
-extern int mkfifo_main(int argc, char **argv)
+int mkfifo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mkfifo_main(int argc UNUSED_PARAM, char **argv)
{
mode_t mode;
int retval = EXIT_SUCCESS;
- mode = getopt_mk_fifo_nod(argc, argv);
+ mode = getopt_mk_fifo_nod(argv);
- if (!*(argv += optind)) {
+ argv += optind;
+ if (!*argv) {
bb_show_usage();
}
do {
if (mkfifo(*argv, mode) < 0) {
- bb_perror_msg("%s", *argv); /* Avoid multibyte problems. */
+ bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */
retval = EXIT_FAILURE;
}
} while (*++argv);
diff --git a/release/src/router/busybox/coreutils/mknod.c b/release/src/router/busybox/coreutils/mknod.c
index d5e9e17f..0c694948 100644
--- a/release/src/router/busybox/coreutils/mknod.c
+++ b/release/src/router/busybox/coreutils/mknod.c
@@ -4,59 +4,53 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "busybox.h"
+#include <sys/sysmacros.h> // For makedev
+
+#include "libbb.h"
#include "libcoreutils/coreutils.h"
-static const char modes_chars[] = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 };
+static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 };
static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK };
-extern int mknod_main(int argc, char **argv)
+int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mknod_main(int argc, char **argv)
{
mode_t mode;
dev_t dev;
const char *name;
- mode = getopt_mk_fifo_nod(argc, argv);
+ mode = getopt_mk_fifo_nod(argv);
argv += optind;
argc -= optind;
- if ((argc >= 2) && ((name = strchr(modes_chars, argv[1][0])) != NULL)) {
- mode |= modes_cubp[(int)(name[4])];
+ if (argc >= 2) {
+ name = strchr(modes_chars, argv[1][0]);
+ if (name != NULL) {
+ mode |= modes_cubp[(int)(name[4])];
- dev = 0;
- if ((*name != 'p') && ((argc -= 2) == 2)) {
- dev = (bb_xgetularg10_bnd(argv[2], 0, 255) << 8)
- + bb_xgetularg10_bnd(argv[3], 0, 255);
- }
-
- if (argc == 2) {
- name = *argv;
- if (mknod(name, mode, dev) == 0) {
- return EXIT_SUCCESS;
+ dev = 0;
+ if (*name != 'p') {
+ argc -= 2;
+ if (argc == 2) {
+ /* Autodetect what the system supports; these macros should
+ * optimize out to two constants. */
+ dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)),
+ xatoul_range(argv[3], 0, minor(UINT_MAX)));
+ }
+ }
+
+ if (argc == 2) {
+ name = *argv;
+ if (mknod(name, mode, dev) == 0) {
+ return EXIT_SUCCESS;
+ }
+ bb_simple_perror_msg_and_die(name);
}
- bb_perror_msg_and_die("%s", name);
}
}
bb_show_usage();
diff --git a/release/src/router/busybox/coreutils/mv.c b/release/src/router/busybox/coreutils/mv.c
index 55da2cc6..be10b030 100644
--- a/release/src/router/busybox/coreutils/mv.c
+++ b/release/src/router/busybox/coreutils/mv.c
@@ -3,21 +3,9 @@
* Mini mv implementation for busybox
*
* Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
@@ -25,119 +13,123 @@
* Size reduction and improved error checking.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include "busybox.h"
+#include "libbb.h"
#include "libcoreutils/coreutils.h"
-static const struct option mv_long_options[] = {
- { "interactive", 0, NULL, 'i' },
- { "force", 0, NULL, 'f' },
- { 0, 0, 0, 0 }
-};
+#if ENABLE_FEATURE_MV_LONG_OPTIONS
+static const char mv_longopts[] ALIGN1 =
+ "interactive\0" No_argument "i"
+ "force\0" No_argument "f"
+ ;
+#endif
-static const char mv_getopt_short_option[] = "fi";
#define OPT_FILEUTILS_FORCE 1
#define OPT_FILEUTILS_INTERACTIVE 2
-static const char fmt[] = "cannot overwrite %sdirectory with %sdirectory";
-
-extern int mv_main(int argc, char **argv)
+int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int mv_main(int argc, char **argv)
{
- struct stat source_stat;
struct stat dest_stat;
const char *last;
const char *dest;
+ unsigned flags;
int dest_exists;
- int source_exists;
- unsigned long flags;
int status = 0;
+ int copy_flag = 0;
- bb_applet_long_options = mv_long_options;
- bb_opt_complementaly = "f-i:i-f";
- flags = bb_getopt_ulflags(argc, argv, mv_getopt_short_option);
-
- if (optind + 2 > argc)
- bb_show_usage();
-
- last = argv[argc - 1];
+#if ENABLE_FEATURE_MV_LONG_OPTIONS
+ applet_long_options = mv_longopts;
+#endif
+ // Need at least two arguments
+ // -f unsets -i, -i unsets -f
+ opt_complementary = "-2:f-i:i-f";
+ flags = getopt32(argv, "fi");
+ argc -= optind;
argv += optind;
+ last = argv[argc - 1];
- if (optind + 2 == argc) {
- if ((dest_exists = cp_mv_stat(last, &dest_stat)) < 0) {
- return 1;
+ if (argc == 2) {
+ dest_exists = cp_mv_stat(last, &dest_stat);
+ if (dest_exists < 0) {
+ return EXIT_FAILURE;
}
- if (!(dest_exists & 2)) {
+ if (!(dest_exists & 2)) { /* last is not a directory */
dest = last;
goto DO_MOVE;
}
}
-
- do {
- dest = concat_path_file(last, bb_get_last_path_component(*argv));
- if ((dest_exists = cp_mv_stat(dest, &dest_stat)) < 0) {
+ do {
+ dest = concat_path_file(last, bb_get_last_path_component_strip(*argv));
+ dest_exists = cp_mv_stat(dest, &dest_stat);
+ if (dest_exists < 0) {
goto RET_1;
}
- DO_MOVE:
-
- if (dest_exists && !(flags & OPT_FILEUTILS_FORCE) &&
- ((access(dest, W_OK) < 0 && isatty(0)) ||
- (flags & OPT_FILEUTILS_INTERACTIVE))) {
- if (fprintf(stderr, "mv: overwrite `%s'? ", dest) < 0) {
- goto RET_1; /* Ouch! fprintf failed! */
- }
- if (!bb_ask_confirmation())
- goto RET_0;
- }
-
+ DO_MOVE:
+ if (dest_exists
+ && !(flags & OPT_FILEUTILS_FORCE)
+ && ((access(dest, W_OK) < 0 && isatty(0))
+ || (flags & OPT_FILEUTILS_INTERACTIVE))
+ ) {
+ if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) {
+ goto RET_1; /* Ouch! fprintf failed! */
+ }
+ if (!bb_ask_confirmation()) {
+ goto RET_0;
+ }
+ }
if (rename(*argv, dest) < 0) {
- if (errno != EXDEV) {
- bb_perror_msg("unable to rename `%s'", *argv);
- } else if ((source_exists = cp_mv_stat(*argv, &source_stat)) >= 0) {
+ struct stat source_stat;
+ int source_exists;
+
+ if (errno != EXDEV
+ || (source_exists = cp_mv_stat2(*argv, &source_stat, lstat)) < 1
+ ) {
+ bb_perror_msg("cannot rename '%s'", *argv);
+ } else {
+ static const char fmt[] ALIGN1 =
+ "cannot overwrite %sdirectory with %sdirectory";
+
if (dest_exists) {
- if (dest_exists & 2) {
- if (!(source_exists & 2)) {
+ if (dest_exists == 3) {
+ if (source_exists != 3) {
bb_error_msg(fmt, "", "non-");
goto RET_1;
}
} else {
- if (source_exists & 2) {
+ if (source_exists == 3) {
bb_error_msg(fmt, "non-", "");
goto RET_1;
}
}
if (unlink(dest) < 0) {
- bb_perror_msg("cannot remove `%s'", dest);
+ bb_perror_msg("cannot remove '%s'", dest);
goto RET_1;
}
}
-
- if ((copy_file(*argv, dest,
- FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS) >= 0)
- && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)
- ) {
+ /* FILEUTILS_RECUR also prevents nasties like
+ * "read from device and write contents to dst"
+ * instead of "create same device node" */
+ copy_flag = FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS;
+#if ENABLE_SELINUX
+ copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT;
+#endif
+ if ((copy_file(*argv, dest, copy_flag) >= 0)
+ && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)
+ ) {
goto RET_0;
}
-
}
- RET_1:
+ RET_1:
status = 1;
}
-
- RET_0:
+ RET_0:
if (dest != last) {
free((void *) dest);
}
-
} while (*++argv != last);
-
- exit(status);
+
+ return status;
}
diff --git a/release/src/router/busybox/coreutils/nice.c b/release/src/router/busybox/coreutils/nice.c
new file mode 100644
index 00000000..d24a95b4
--- /dev/null
+++ b/release/src/router/busybox/coreutils/nice.c
@@ -0,0 +1,55 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * nice implementation for busybox
+ *
+ * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include <sys/resource.h>
+#include "libbb.h"
+
+int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nice_main(int argc, char **argv)
+{
+ int old_priority, adjustment;
+
+ old_priority = getpriority(PRIO_PROCESS, 0);
+
+ if (!*++argv) { /* No args, so (GNU) output current nice value. */
+ printf("%d\n", old_priority);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+ }
+
+ adjustment = 10; /* Set default adjustment. */
+
+ if (argv[0][0] == '-') {
+ if (argv[0][1] == 'n') { /* -n */
+ if (argv[0][2]) { /* -nNNNN (w/o space) */
+ argv[0] += 2; argv--; argc++;
+ }
+ } else { /* -NNN (NNN may be negative) == -n NNN */
+ argv[0] += 1; argv--; argc++;
+ }
+ if (argc < 4) { /* Missing priority and/or utility! */
+ bb_show_usage();
+ }
+ adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2);
+ argv += 2;
+ }
+
+ { /* Set our priority. */
+ int prio = old_priority + adjustment;
+
+ if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
+ bb_perror_msg_and_die("setpriority(%d)", prio);
+ }
+ }
+
+ BB_EXECVP(*argv, argv); /* Now exec the desired program. */
+
+ /* The exec failed... */
+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */
+ bb_simple_perror_msg_and_die(*argv);
+}
diff --git a/release/src/router/busybox/coreutils/nohup.c b/release/src/router/busybox/coreutils/nohup.c
new file mode 100644
index 00000000..f44e2af6
--- /dev/null
+++ b/release/src/router/busybox/coreutils/nohup.c
@@ -0,0 +1,78 @@
+/* vi: set sw=4 ts=4: */
+/* nohup - invoke a utility immune to hangups.
+ *
+ * Busybox version based on nohup specification at
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/nohup.html
+ *
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ * Copyright 2006 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* Compat info: nohup (GNU coreutils 6.8) does this:
+# nohup true
+nohup: ignoring input and appending output to `nohup.out'
+# nohup true 1>/dev/null
+nohup: ignoring input and redirecting stderr to stdout
+# nohup true 2>zz
+# cat zz
+nohup: ignoring input and appending output to `nohup.out'
+# nohup true 2>zz 1>/dev/null
+# cat zz
+nohup: ignoring input
+# nohup true </dev/null 1>/dev/null
+nohup: redirecting stderr to stdout
+# nohup true </dev/null 2>zz 1>/dev/null
+# cat zz
+ (nothing)
+#
+*/
+
+int nohup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int nohup_main(int argc, char **argv)
+{
+ const char *nohupout;
+ char *home;
+
+ xfunc_error_retval = 127;
+
+ if (argc < 2) bb_show_usage();
+
+ /* If stdin is a tty, detach from it. */
+ if (isatty(STDIN_FILENO)) {
+ /* bb_error_msg("ignoring input"); */
+ close(STDIN_FILENO);
+ xopen(bb_dev_null, O_RDONLY); /* will be fd 0 (STDIN_FILENO) */
+ }
+
+ nohupout = "nohup.out";
+ /* Redirect stdout to nohup.out, either in "." or in "$HOME". */
+ if (isatty(STDOUT_FILENO)) {
+ close(STDOUT_FILENO);
+ if (open(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR) < 0) {
+ home = getenv("HOME");
+ if (home) {
+ nohupout = concat_path_file(home, nohupout);
+ xopen3(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR);
+ } else {
+ xopen(bb_dev_null, O_RDONLY); /* will be fd 1 */
+ }
+ }
+ bb_error_msg("appending output to %s", nohupout);
+ }
+
+ /* If we have a tty on stderr, redirect to stdout. */
+ if (isatty(STDERR_FILENO)) {
+ /* if (stdout_wasnt_a_tty)
+ bb_error_msg("redirecting stderr to stdout"); */
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ }
+
+ signal(SIGHUP, SIG_IGN);
+
+ BB_EXECVP(argv[1], argv+1);
+ bb_simple_perror_msg_and_die(argv[1]);
+}
diff --git a/release/src/router/busybox/coreutils/od.c b/release/src/router/busybox/coreutils/od.c
index b18c53c3..e4179a36 100644
--- a/release/src/router/busybox/coreutils/od.c
+++ b/release/src/router/busybox/coreutils/od.c
@@ -1,3 +1,4 @@
+/* vi: set sw=4 ts=4: */
/*
* od implementation for busybox
* Based on code from util-linux v 2.11l
@@ -5,37 +6,27 @@
* Copyright (c) 1990
* The Regents of the University of California. All rights reserved.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
* Original copyright notice is retained at the end of this file.
*/
-#include <ctype.h>
-#include <string.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include "busybox.h"
+
+#include "libbb.h"
+#if ENABLE_DESKTOP
+/* This one provides -t (busybox's own build script needs it) */
+#include "od_bloaty.c"
+#else
+
#include "dump.h"
-#define isdecdigit(c) (isdigit)(c)
+#define isdecdigit(c) isdigit(c)
#define ishexdigit(c) (isxdigit)(c)
static void
-odoffset(int argc, char ***argvp)
+odoffset(dumper_t *dumper, int argc, char ***argvp)
{
- register char *num, *p;
+ char *num, *p;
int base;
char *end;
@@ -66,7 +57,7 @@ odoffset(int argc, char ***argvp)
base = 0;
/*
- * bb_dump_skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
+ * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
* set base.
*/
if (p[0] == '+')
@@ -79,11 +70,13 @@ odoffset(int argc, char ***argvp)
base = 16;
}
- /* bb_dump_skip over the number */
+ /* skip over the number */
if (base == 16)
- for (num = p; ishexdigit(*p); ++p);
+ for (num = p; ishexdigit(*p); ++p)
+ continue;
else
- for (num = p; isdecdigit(*p); ++p);
+ for (num = p; isdecdigit(*p); ++p)
+ continue;
/* check for no number */
if (num == p)
@@ -96,23 +89,23 @@ odoffset(int argc, char ***argvp)
base = 10;
}
- bb_dump_skip = strtol(num, &end, base ? base : 8);
+ dumper->dump_skip = strtol(num, &end, base ? base : 8);
/* if end isn't the same as p, we got a non-octal digit */
if (end != p)
- bb_dump_skip = 0;
+ dumper->dump_skip = 0;
else {
if (*p) {
if (*p == 'b') {
- bb_dump_skip *= 512;
+ dumper->dump_skip *= 512;
++p;
} else if (*p == 'B') {
- bb_dump_skip *= 1024;
+ dumper->dump_skip *= 1024;
++p;
}
}
if (*p)
- bb_dump_skip = 0;
+ dumper->dump_skip = 0;
else {
++*argvp;
/*
@@ -129,9 +122,9 @@ odoffset(int argc, char ***argvp)
}
if (base == 10) {
x_or_d = 'd';
- DO_X_OR_D:
- bb_dump_fshead->nextfu->fmt[TYPE_OFFSET]
- = bb_dump_fshead->nextfs->nextfu->fmt[TYPE_OFFSET]
+ DO_X_OR_D:
+ dumper->fshead->nextfu->fmt[TYPE_OFFSET]
+ = dumper->fshead->nextfs->nextfu->fmt[TYPE_OFFSET]
= x_or_d;
}
}
@@ -139,7 +132,7 @@ odoffset(int argc, char ***argvp)
}
}
-static const char * const add_strings[] = {
+static const char *const add_strings[] = {
"16/1 \"%3_u \" \"\\n\"", /* a */
"8/2 \" %06o \" \"\\n\"", /* B, o */
"16/1 \"%03o \" \"\\n\"", /* b */
@@ -155,51 +148,52 @@ static const char * const add_strings[] = {
"4/4 \" %011o \" \"\\n\"", /* O */
};
-static const signed char od_opts[] = "aBbcDdeFfHhIiLlOovXx";
+static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv";
-static const signed char od_o2si[] = {
+static const char od_o2si[] ALIGN1 = {
0, 1, 2, 3, 5,
4, 6, 6, 7, 8,
9, 0xa, 0xb, 0xa, 0xa,
- 0xb, 1, -1, 8, 9,
+ 0xb, 1, 8, 9,
};
+int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int od_main(int argc, char **argv)
{
int ch;
int first = 1;
- signed char *p;
- bb_dump_vflag = FIRST;
- bb_dump_length = -1;
+ char *p;
+ dumper_t *dumper = alloc_dumper();
while ((ch = getopt(argc, argv, od_opts)) > 0) {
- if (((p = strchr(od_opts, ch)) != NULL) && (*p >= 0)) {
+ if (ch == 'v') {
+ dumper->dump_vflag = ALL;
+ } else if (((p = strchr(od_opts, ch)) != NULL) && (*p != '\0')) {
if (first) {
first = 0;
- bb_dump_add("\"%07.7_Ao\n\"");
- bb_dump_add("\"%07.7_ao \"");
+ bb_dump_add(dumper, "\"%07.7_Ao\n\"");
+ bb_dump_add(dumper, "\"%07.7_ao \"");
} else {
- bb_dump_add("\" \"");
+ bb_dump_add(dumper, "\" \"");
}
- bb_dump_add(add_strings[od_o2si[(int)(p-od_opts)]]);
- } else if (ch == 'v') {
- bb_dump_vflag = ALL;
+ bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]);
} else { /* P, p, s, w, or other unhandled */
bb_show_usage();
}
}
- if (!bb_dump_fshead) {
- bb_dump_add("\"%07.7_Ao\n\"");
- bb_dump_add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\"");
+ if (!dumper->fshead) {
+ bb_dump_add(dumper, "\"%07.7_Ao\n\"");
+ bb_dump_add(dumper, "\"%07.7_ao \" 8/2 \"%06o \" \"\\n\"");
}
argc -= optind;
argv += optind;
- odoffset(argc, &argv);
+ odoffset(dumper, argc, &argv);
- return(bb_dump_dump(argv));
+ return bb_dump_dump(dumper, argv);
}
+#endif /* ENABLE_DESKTOP */
/*-
* Copyright (c) 1990 The Regents of the University of California.
diff --git a/release/src/router/busybox/coreutils/od_bloaty.c b/release/src/router/busybox/coreutils/od_bloaty.c
new file mode 100644
index 00000000..eb457985
--- /dev/null
+++ b/release/src/router/busybox/coreutils/od_bloaty.c
@@ -0,0 +1,1428 @@
+/* od -- dump files in octal and other formats
+ Copyright (C) 92, 1995-2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jim Meyering. */
+
+/* Busyboxed by Denys Vlasenko
+
+Based on od.c from coreutils-5.2.1
+Top bloat sources:
+
+00000073 t parse_old_offset
+0000007b t get_lcm
+00000090 r long_options
+00000092 t print_named_ascii
+000000bf t print_ascii
+00000168 t write_block
+00000366 t decode_format_string
+00000a71 T od_main
+
+Tested for compat with coreutils 6.3
+using this script. Minor differences fixed.
+
+#!/bin/sh
+echo STD
+time /path/to/coreutils/od \
+...params... \
+>std
+echo Exit code $?
+echo BBOX
+time ./busybox od \
+...params... \
+>bbox
+echo Exit code $?
+diff -u -a std bbox >bbox.diff || { echo Different!; sleep 1; }
+
+*/
+
+#include "libbb.h"
+
+#define assert(a) ((void)0)
+
+/* Check for 0x7f is a coreutils 6.3 addition */
+#define ISPRINT(c) (((c)>=' ') && (c) != 0x7f)
+
+typedef long double longdouble_t;
+typedef unsigned long long ulonglong_t;
+typedef long long llong;
+
+#if ENABLE_LFS
+# define xstrtooff_sfx xstrtoull_sfx
+#else
+# define xstrtooff_sfx xstrtoul_sfx
+#endif
+
+/* The default number of input bytes per output line. */
+#define DEFAULT_BYTES_PER_BLOCK 16
+
+/* The number of decimal digits of precision in a float. */
+#ifndef FLT_DIG
+# define FLT_DIG 7
+#endif
+
+/* The number of decimal digits of precision in a double. */
+#ifndef DBL_DIG
+# define DBL_DIG 15
+#endif
+
+/* The number of decimal digits of precision in a long double. */
+#ifndef LDBL_DIG
+# define LDBL_DIG DBL_DIG
+#endif
+
+enum size_spec {
+ NO_SIZE,
+ CHAR,
+ SHORT,
+ INT,
+ LONG,
+ LONG_LONG,
+ FLOAT_SINGLE,
+ FLOAT_DOUBLE,
+ FLOAT_LONG_DOUBLE,
+ N_SIZE_SPECS
+};
+
+enum output_format {
+ SIGNED_DECIMAL,
+ UNSIGNED_DECIMAL,
+ OCTAL,
+ HEXADECIMAL,
+ FLOATING_POINT,
+ NAMED_CHARACTER,
+ CHARACTER
+};
+
+/* Each output format specification (from '-t spec' or from
+ old-style options) is represented by one of these structures. */
+struct tspec {
+ enum output_format fmt;
+ enum size_spec size;
+ void (*print_function) (size_t, const char *, const char *);
+ char *fmt_string;
+ int hexl_mode_trailer;
+ int field_width;
+};
+
+/* Convert the number of 8-bit bytes of a binary representation to
+ the number of characters (digits + sign if the type is signed)
+ required to represent the same quantity in the specified base/type.
+ For example, a 32-bit (4-byte) quantity may require a field width
+ as wide as the following for these types:
+ 11 unsigned octal
+ 11 signed decimal
+ 10 unsigned decimal
+ 8 unsigned hexadecimal */
+
+static const uint8_t bytes_to_oct_digits[] ALIGN1 =
+{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43};
+
+static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 =
+{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40};
+
+static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 =
+{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39};
+
+static const uint8_t bytes_to_hex_digits[] ALIGN1 =
+{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32};
+
+/* Convert enum size_spec to the size of the named type. */
+static const signed char width_bytes[] ALIGN1 = {
+ -1,
+ sizeof(char),
+ sizeof(short),
+ sizeof(int),
+ sizeof(long),
+ sizeof(ulonglong_t),
+ sizeof(float),
+ sizeof(double),
+ sizeof(longdouble_t)
+};
+/* Ensure that for each member of 'enum size_spec' there is an
+ initializer in the width_bytes array. */
+struct ERR_width_bytes_has_bad_size {
+ char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1];
+};
+
+static smallint flag_dump_strings;
+/* Non-zero if an old-style 'pseudo-address' was specified. */
+static smallint flag_pseudo_start;
+static smallint limit_bytes_to_format;
+/* When zero and two or more consecutive blocks are equal, format
+ only the first block and output an asterisk alone on the following
+ line to indicate that identical blocks have been elided. */
+static smallint verbose;
+static smallint ioerror;
+
+static size_t string_min;
+
+/* An array of specs describing how to format each input block. */
+static size_t n_specs;
+static struct tspec *spec;
+
+/* Function that accepts an address and an optional following char,
+ and prints the address and char to stdout. */
+static void (*format_address)(off_t, char);
+/* The difference between the old-style pseudo starting address and
+ the number of bytes to skip. */
+static off_t pseudo_offset;
+/* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all
+ input is formatted. */
+
+/* The number of input bytes formatted per output line. It must be
+ a multiple of the least common multiple of the sizes associated with
+ the specified output types. It should be as large as possible, but
+ no larger than 16 -- unless specified with the -w option. */
+static unsigned bytes_per_block = 32; /* have to use unsigned, not size_t */
+
+/* A NULL-terminated list of the file-arguments from the command line. */
+static const char *const *file_list;
+
+/* The input stream associated with the current file. */
+static FILE *in_stream;
+
+#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t)
+static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = {
+ [sizeof(char)] = CHAR,
+#if USHRT_MAX != UCHAR_MAX
+ [sizeof(short)] = SHORT,
+#endif
+#if UINT_MAX != USHRT_MAX
+ [sizeof(int)] = INT,
+#endif
+#if ULONG_MAX != UINT_MAX
+ [sizeof(long)] = LONG,
+#endif
+#if ULLONG_MAX != ULONG_MAX
+ [sizeof(ulonglong_t)] = LONG_LONG,
+#endif
+};
+
+#define MAX_FP_TYPE_SIZE sizeof(longdouble_t)
+static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = {
+ /* gcc seems to allow repeated indexes. Last one stays */
+ [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE,
+ [sizeof(double)] = FLOAT_DOUBLE,
+ [sizeof(float)] = FLOAT_SINGLE
+};
+
+
+static unsigned
+gcd(unsigned u, unsigned v)
+{
+ unsigned t;
+ while (v != 0) {
+ t = u % v;
+ u = v;
+ v = t;
+ }
+ return u;
+}
+
+/* Compute the least common multiple of U and V. */
+static unsigned
+lcm(unsigned u, unsigned v) {
+ unsigned t = gcd(u, v);
+ if (t == 0)
+ return 0;
+ return u * v / t;
+}
+
+static void
+print_s_char(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ while (n_bytes--) {
+ int tmp = *(signed char *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned char);
+ }
+}
+
+static void
+print_char(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned char *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned char);
+ }
+}
+
+static void
+print_s_short(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(signed short);
+ while (n_bytes--) {
+ int tmp = *(signed short *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned short);
+ }
+}
+
+static void
+print_short(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned short);
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned short *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned short);
+ }
+}
+
+static void
+print_int(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned);
+ while (n_bytes--) {
+ unsigned tmp = *(unsigned *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned);
+ }
+}
+
+#if UINT_MAX == ULONG_MAX
+# define print_long print_int
+#else
+static void
+print_long(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(unsigned long);
+ while (n_bytes--) {
+ unsigned long tmp = *(unsigned long *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(unsigned long);
+ }
+}
+#endif
+
+#if ULONG_MAX == ULLONG_MAX
+# define print_long_long print_long
+#else
+static void
+print_long_long(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(ulonglong_t);
+ while (n_bytes--) {
+ ulonglong_t tmp = *(ulonglong_t *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(ulonglong_t);
+ }
+}
+#endif
+
+static void
+print_float(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(float);
+ while (n_bytes--) {
+ float tmp = *(float *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(float);
+ }
+}
+
+static void
+print_double(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(double);
+ while (n_bytes--) {
+ double tmp = *(double *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(double);
+ }
+}
+
+static void
+print_long_double(size_t n_bytes, const char *block, const char *fmt_string)
+{
+ n_bytes /= sizeof(longdouble_t);
+ while (n_bytes--) {
+ longdouble_t tmp = *(longdouble_t *) block;
+ printf(fmt_string, tmp);
+ block += sizeof(longdouble_t);
+ }
+}
+
+/* print_[named]_ascii are optimized for speed.
+ * Remember, someday you may want to pump gigabytes through this thing.
+ * Saving a dozen of .text bytes here is counter-productive */
+
+static void
+print_named_ascii(size_t n_bytes, const char *block,
+ const char *unused_fmt_string UNUSED_PARAM)
+{
+ /* Names for some non-printing characters. */
+ static const char charname[33][3] ALIGN1 = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ " bs", " ht", " nl", " vt", " ff", " cr", " so", " si",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", " em", "sub", "esc", " fs", " gs", " rs", " us",
+ " sp"
+ };
+ // buf[N] pos: 01234 56789
+ char buf[12] = " x\0 0xx\0";
+ // actually " x\0 xxx\0", but I want to share the string with below.
+ // [12] because we take three 32bit stack slots anyway, and
+ // gcc is too dumb to initialize with constant stores,
+ // it copies initializer from rodata. Oh well.
+
+ while (n_bytes--) {
+ unsigned masked_c = *(unsigned char *) block++;
+
+ masked_c &= 0x7f;
+ if (masked_c == 0x7f) {
+ fputs(" del", stdout);
+ continue;
+ }
+ if (masked_c > ' ') {
+ buf[3] = masked_c;
+ fputs(buf, stdout);
+ continue;
+ }
+ /* Why? Because printf(" %3.3s") is much slower... */
+ buf[6] = charname[masked_c][0];
+ buf[7] = charname[masked_c][1];
+ buf[8] = charname[masked_c][2];
+ fputs(buf+5, stdout);
+ }
+}
+
+static void
+print_ascii(size_t n_bytes, const char *block,
+ const char *unused_fmt_string UNUSED_PARAM)
+{
+ // buf[N] pos: 01234 56789
+ char buf[12] = " x\0 0xx\0";
+
+ while (n_bytes--) {
+ const char *s;
+ unsigned c = *(unsigned char *) block++;
+
+ if (ISPRINT(c)) {
+ buf[3] = c;
+ fputs(buf, stdout);
+ continue;
+ }
+ switch (c) {
+ case '\0':
+ s = " \\0";
+ break;
+ case '\007':
+ s = " \\a";
+ break;
+ case '\b':
+ s = " \\b";
+ break;
+ case '\f':
+ s = " \\f";
+ break;
+ case '\n':
+ s = " \\n";
+ break;
+ case '\r':
+ s = " \\r";
+ break;
+ case '\t':
+ s = " \\t";
+ break;
+ case '\v':
+ s = " \\v";
+ break;
+ case '\x7f':
+ s = " 177";
+ break;
+ default: /* c is never larger than 040 */
+ buf[7] = (c >> 3) + '0';
+ buf[8] = (c & 7) + '0';
+ s = buf + 5;
+ }
+ fputs(s, stdout);
+ }
+}
+
+/* Given a list of one or more input filenames FILE_LIST, set the global
+ file pointer IN_STREAM and the global string INPUT_FILENAME to the
+ first one that can be successfully opened. Modify FILE_LIST to
+ reference the next filename in the list. A file name of "-" is
+ interpreted as standard input. If any file open fails, give an error
+ message and return nonzero. */
+
+static void
+open_next_file(void)
+{
+ while (1) {
+ if (!*file_list)
+ return;
+ in_stream = fopen_or_warn_stdin(*file_list++);
+ if (in_stream) {
+ break;
+ }
+ ioerror = 1;
+ }
+
+ if (limit_bytes_to_format && !flag_dump_strings)
+ setbuf(in_stream, NULL);
+}
+
+/* Test whether there have been errors on in_stream, and close it if
+ it is not standard input. Return nonzero if there has been an error
+ on in_stream or stdout; return zero otherwise. This function will
+ report more than one error only if both a read and a write error
+ have occurred. IN_ERRNO, if nonzero, is the error number
+ corresponding to the most recent action for IN_STREAM. */
+
+static void
+check_and_close(void)
+{
+ if (in_stream) {
+ if (ferror(in_stream)) {
+ bb_error_msg("%s: read error", (in_stream == stdin)
+ ? bb_msg_standard_input
+ : file_list[-1]
+ );
+ ioerror = 1;
+ }
+ fclose_if_not_stdin(in_stream);
+ in_stream = NULL;
+ }
+
+ if (ferror(stdout)) {
+ bb_error_msg("write error");
+ ioerror = 1;
+ }
+}
+
+/* If S points to a single valid modern od format string, put
+ a description of that format in *TSPEC, return pointer to
+ character following the just-decoded format.
+ For example, if S were "d4afL", we will return a rtp to "afL"
+ and *TSPEC would be
+ {
+ fmt = SIGNED_DECIMAL;
+ size = INT or LONG; (whichever integral_type_size[4] resolves to)
+ print_function = print_int; (assuming size == INT)
+ fmt_string = "%011d%c";
+ }
+ S_ORIG is solely for reporting errors. It should be the full format
+ string argument. */
+
+static const char *
+decode_one_format(const char *s_orig, const char *s, struct tspec *tspec)
+{
+ enum size_spec size_spec;
+ unsigned size;
+ enum output_format fmt;
+ const char *p;
+ char *end;
+ char *fmt_string = NULL;
+ void (*print_function) (size_t, const char *, const char *);
+ unsigned c;
+ unsigned field_width = 0;
+ int pos;
+
+
+ switch (*s) {
+ case 'd':
+ case 'o':
+ case 'u':
+ case 'x': {
+ static const char CSIL[] ALIGN1 = "CSIL";
+
+ c = *s++;
+ p = strchr(CSIL, *s);
+ if (!p) {
+ size = sizeof(int);
+ if (isdigit(s[0])) {
+ size = bb_strtou(s, &end, 0);
+ if (errno == ERANGE
+ || MAX_INTEGRAL_TYPE_SIZE < size
+ || integral_type_size[size] == NO_SIZE
+ ) {
+ bb_error_msg_and_die("invalid type string '%s'; "
+ "%u-byte %s type is not supported",
+ s_orig, size, "integral");
+ }
+ s = end;
+ }
+ } else {
+ static const uint8_t CSIL_sizeof[4] = {
+ sizeof(char),
+ sizeof(short),
+ sizeof(int),
+ sizeof(long),
+ };
+ size = CSIL_sizeof[p - CSIL];
+ s++; /* skip C/S/I/L */
+ }
+
+#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \
+ ((Spec) == LONG_LONG ? (Max_format) \
+ : ((Spec) == LONG ? (Long_format) : (Min_format)))
+
+#define FMT_BYTES_ALLOCATED 9
+ size_spec = integral_type_size[size];
+
+ {
+ static const char doux[] ALIGN1 = "doux";
+ static const char doux_fmt_letter[][4] = {
+ "lld", "llo", "llu", "llx"
+ };
+ static const enum output_format doux_fmt[] = {
+ SIGNED_DECIMAL,
+ OCTAL,
+ UNSIGNED_DECIMAL,
+ HEXADECIMAL,
+ };
+ static const uint8_t *const doux_bytes_to_XXX[] = {
+ bytes_to_signed_dec_digits,
+ bytes_to_oct_digits,
+ bytes_to_unsigned_dec_digits,
+ bytes_to_hex_digits,
+ };
+ static const char doux_fmtstring[][sizeof(" %%0%u%s")] = {
+ " %%%u%s",
+ " %%0%u%s",
+ " %%%u%s",
+ " %%0%u%s",
+ };
+
+ pos = strchr(doux, c) - doux;
+ fmt = doux_fmt[pos];
+ field_width = doux_bytes_to_XXX[pos][size];
+ p = doux_fmt_letter[pos] + 2;
+ if (size_spec == LONG) p--;
+ if (size_spec == LONG_LONG) p -= 2;
+ fmt_string = xasprintf(doux_fmtstring[pos], field_width, p);
+ }
+
+ switch (size_spec) {
+ case CHAR:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_char
+ : print_char);
+ break;
+ case SHORT:
+ print_function = (fmt == SIGNED_DECIMAL
+ ? print_s_short
+ : print_short);
+ break;
+ case INT:
+ print_function = print_int;
+ break;
+ case LONG:
+ print_function = print_long;
+ break;
+ default: /* case LONG_LONG: */
+ print_function = print_long_long;
+ break;
+ }
+ break;
+ }
+
+ case 'f': {
+ static const char FDL[] ALIGN1 = "FDL";
+
+ fmt = FLOATING_POINT;
+ ++s;
+ p = strchr(FDL, *s);
+ if (!p) {
+ size = sizeof(double);
+ if (isdigit(s[0])) {
+ size = bb_strtou(s, &end, 0);
+ if (errno == ERANGE || size > MAX_FP_TYPE_SIZE
+ || fp_type_size[size] == NO_SIZE
+ ) {
+ bb_error_msg_and_die("invalid type string '%s'; "
+ "%u-byte %s type is not supported",
+ s_orig, size, "floating point");
+ }
+ s = end;
+ }
+ } else {
+ static const uint8_t FDL_sizeof[] = {
+ sizeof(float),
+ sizeof(double),
+ sizeof(longdouble_t),
+ };
+
+ size = FDL_sizeof[p - FDL];
+ }
+
+ size_spec = fp_type_size[size];
+
+ switch (size_spec) {
+ case FLOAT_SINGLE:
+ print_function = print_float;
+ field_width = FLT_DIG + 8;
+ /* Don't use %#e; not all systems support it. */
+ fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG);
+ break;
+ case FLOAT_DOUBLE:
+ print_function = print_double;
+ field_width = DBL_DIG + 8;
+ fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG);
+ break;
+ default: /* case FLOAT_LONG_DOUBLE: */
+ print_function = print_long_double;
+ field_width = LDBL_DIG + 8;
+ fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG);
+ break;
+ }
+ break;
+ }
+
+ case 'a':
+ ++s;
+ fmt = NAMED_CHARACTER;
+ size_spec = CHAR;
+ print_function = print_named_ascii;
+ field_width = 3;
+ break;
+ case 'c':
+ ++s;
+ fmt = CHARACTER;
+ size_spec = CHAR;
+ print_function = print_ascii;
+ field_width = 3;
+ break;
+ default:
+ bb_error_msg_and_die("invalid character '%c' "
+ "in type string '%s'", *s, s_orig);
+ }
+
+ tspec->size = size_spec;
+ tspec->fmt = fmt;
+ tspec->print_function = print_function;
+ tspec->fmt_string = fmt_string;
+
+ tspec->field_width = field_width;
+ tspec->hexl_mode_trailer = (*s == 'z');
+ if (tspec->hexl_mode_trailer)
+ s++;
+
+ return s;
+}
+
+/* Decode the modern od format string S. Append the decoded
+ representation to the global array SPEC, reallocating SPEC if
+ necessary. */
+
+static void
+decode_format_string(const char *s)
+{
+ const char *s_orig = s;
+
+ while (*s != '\0') {
+ struct tspec tspec;
+ const char *next;
+
+ next = decode_one_format(s_orig, s, &tspec);
+
+ assert(s != next);
+ s = next;
+ spec = xrealloc_vector(spec, 4, n_specs);
+ memcpy(&spec[n_specs], &tspec, sizeof(spec[0]));
+ n_specs++;
+ }
+}
+
+/* Given a list of one or more input filenames FILE_LIST, set the global
+ file pointer IN_STREAM to position N_SKIP in the concatenation of
+ those files. If any file operation fails or if there are fewer than
+ N_SKIP bytes in the combined input, give an error message and return
+ nonzero. When possible, use seek rather than read operations to
+ advance IN_STREAM. */
+
+static void
+skip(off_t n_skip)
+{
+ if (n_skip == 0)
+ return;
+
+ while (in_stream) { /* !EOF */
+ struct stat file_stats;
+
+ /* First try seeking. For large offsets, this extra work is
+ worthwhile. If the offset is below some threshold it may be
+ more efficient to move the pointer by reading. There are two
+ issues when trying to seek:
+ - the file must be seekable.
+ - before seeking to the specified position, make sure
+ that the new position is in the current file.
+ Try to do that by getting file's size using fstat.
+ But that will work only for regular files. */
+
+ /* The st_size field is valid only for regular files
+ (and for symbolic links, which cannot occur here).
+ If the number of bytes left to skip is at least
+ as large as the size of the current file, we can
+ decrement n_skip and go on to the next file. */
+ if (fstat(fileno(in_stream), &file_stats) == 0
+ && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0
+ ) {
+ if (file_stats.st_size < n_skip) {
+ n_skip -= file_stats.st_size;
+ /* take "check & close / open_next" route */
+ } else {
+ if (fseeko(in_stream, n_skip, SEEK_CUR) != 0)
+ ioerror = 1;
+ return;
+ }
+ } else {
+ /* If it's not a regular file with positive size,
+ position the file pointer by reading. */
+ char buf[1024];
+ size_t n_bytes_to_read = 1024;
+ size_t n_bytes_read;
+
+ while (n_skip > 0) {
+ if (n_skip < n_bytes_to_read)
+ n_bytes_to_read = n_skip;
+ n_bytes_read = fread(buf, 1, n_bytes_to_read, in_stream);
+ n_skip -= n_bytes_read;
+ if (n_bytes_read != n_bytes_to_read)
+ break; /* EOF on this file or error */
+ }
+ }
+ if (n_skip == 0)
+ return;
+
+ check_and_close();
+ open_next_file();
+ }
+
+ if (n_skip)
+ bb_error_msg_and_die("cannot skip past end of combined input");
+}
+
+
+typedef void FN_format_address(off_t address, char c);
+
+static void
+format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM)
+{
+}
+
+static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc";
+/* Corresponds to 'x' above */
+#define address_base_char address_fmt[sizeof(address_fmt)-3]
+/* Corresponds to 'n' above */
+#define address_pad_len_char address_fmt[2]
+
+static void
+format_address_std(off_t address, char c)
+{
+ /* Corresponds to 'c' */
+ address_fmt[sizeof(address_fmt)-2] = c;
+ printf(address_fmt, address);
+}
+
+#if ENABLE_GETOPT_LONG
+/* only used with --traditional */
+static void
+format_address_paren(off_t address, char c)
+{
+ putchar('(');
+ format_address_std(address, ')');
+ if (c) putchar(c);
+}
+
+static void
+format_address_label(off_t address, char c)
+{
+ format_address_std(address, ' ');
+ format_address_paren(address + pseudo_offset, c);
+}
+#endif
+
+static void
+dump_hexl_mode_trailer(size_t n_bytes, const char *block)
+{
+ fputs(" >", stdout);
+ while (n_bytes--) {
+ unsigned c = *(unsigned char *) block++;
+ c = (ISPRINT(c) ? c : '.');
+ putchar(c);
+ }
+ putchar('<');
+}
+
+/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each
+ of the N_SPEC format specs. CURRENT_OFFSET is the byte address of
+ CURR_BLOCK in the concatenation of input files, and it is printed
+ (optionally) only before the output line associated with the first
+ format spec. When duplicate blocks are being abbreviated, the output
+ for a sequence of identical input blocks is the output for the first
+ block followed by an asterisk alone on a line. It is valid to compare
+ the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK.
+ That condition may be false only for the last input block -- and then
+ only when it has not been padded to length BYTES_PER_BLOCK. */
+
+static void
+write_block(off_t current_offset, size_t n_bytes,
+ const char *prev_block, const char *curr_block)
+{
+ static char first = 1;
+ static char prev_pair_equal = 0;
+ size_t i;
+
+ if (!verbose && !first
+ && n_bytes == bytes_per_block
+ && memcmp(prev_block, curr_block, bytes_per_block) == 0
+ ) {
+ if (prev_pair_equal) {
+ /* The two preceding blocks were equal, and the current
+ block is the same as the last one, so print nothing. */
+ } else {
+ puts("*");
+ prev_pair_equal = 1;
+ }
+ } else {
+ first = 0;
+ prev_pair_equal = 0;
+ for (i = 0; i < n_specs; i++) {
+ if (i == 0)
+ format_address(current_offset, '\0');
+ else
+ printf("%*s", address_pad_len_char - '0', "");
+ (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string);
+ if (spec[i].hexl_mode_trailer) {
+ /* space-pad out to full line width, then dump the trailer */
+ int datum_width = width_bytes[spec[i].size];
+ int blank_fields = (bytes_per_block - n_bytes) / datum_width;
+ int field_width = spec[i].field_width + 1;
+ printf("%*s", blank_fields * field_width, "");
+ dump_hexl_mode_trailer(n_bytes, curr_block);
+ }
+ putchar('\n');
+ }
+ }
+}
+
+static void
+read_block(size_t n, char *block, size_t *n_bytes_in_buffer)
+{
+ assert(0 < n && n <= bytes_per_block);
+
+ *n_bytes_in_buffer = 0;
+
+ if (n == 0)
+ return;
+
+ while (in_stream != NULL) { /* EOF. */
+ size_t n_needed;
+ size_t n_read;
+
+ n_needed = n - *n_bytes_in_buffer;
+ n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, in_stream);
+ *n_bytes_in_buffer += n_read;
+ if (n_read == n_needed)
+ break;
+ /* error check is done in check_and_close */
+ check_and_close();
+ open_next_file();
+ }
+}
+
+/* Return the least common multiple of the sizes associated
+ with the format specs. */
+
+static int
+get_lcm(void)
+{
+ size_t i;
+ int l_c_m = 1;
+
+ for (i = 0; i < n_specs; i++)
+ l_c_m = lcm(l_c_m, width_bytes[(int) spec[i].size]);
+ return l_c_m;
+}
+
+#if ENABLE_GETOPT_LONG
+/* If S is a valid traditional offset specification with an optional
+ leading '+' return nonzero and set *OFFSET to the offset it denotes. */
+
+static int
+parse_old_offset(const char *s, off_t *offset)
+{
+ static const struct suffix_mult Bb[] = {
+ { "B", 1024 },
+ { "b", 512 },
+ { }
+ };
+ char *p;
+ int radix;
+
+ /* Skip over any leading '+'. */
+ if (s[0] == '+') ++s;
+
+ /* Determine the radix we'll use to interpret S. If there is a '.',
+ * it's decimal, otherwise, if the string begins with '0X'or '0x',
+ * it's hexadecimal, else octal. */
+ p = strchr(s, '.');
+ radix = 8;
+ if (p) {
+ p[0] = '\0'; /* cheating */
+ radix = 10;
+ } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+ radix = 16;
+
+ *offset = xstrtooff_sfx(s, radix, Bb);
+ if (p) p[0] = '.';
+
+ return (*offset >= 0);
+}
+#endif
+
+/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the
+ formatted block to standard output, and repeat until the specified
+ maximum number of bytes has been read or until all input has been
+ processed. If the last block read is smaller than BYTES_PER_BLOCK
+ and its size is not a multiple of the size associated with a format
+ spec, extend the input block with zero bytes until its length is a
+ multiple of all format spec sizes. Write the final block. Finally,
+ write on a line by itself the offset of the byte after the last byte
+ read. */
+
+static void
+dump(off_t current_offset, off_t end_offset)
+{
+ char *block[2];
+ int idx;
+ size_t n_bytes_read;
+
+ block[0] = xmalloc(2*bytes_per_block);
+ block[1] = block[0] + bytes_per_block;
+
+ idx = 0;
+ if (limit_bytes_to_format) {
+ while (1) {
+ size_t n_needed;
+ if (current_offset >= end_offset) {
+ n_bytes_read = 0;
+ break;
+ }
+ n_needed = MIN(end_offset - current_offset,
+ (off_t) bytes_per_block);
+ read_block(n_needed, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert(n_bytes_read == bytes_per_block);
+ write_block(current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
+ } else {
+ while (1) {
+ read_block(bytes_per_block, block[idx], &n_bytes_read);
+ if (n_bytes_read < bytes_per_block)
+ break;
+ assert(n_bytes_read == bytes_per_block);
+ write_block(current_offset, n_bytes_read,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ idx = !idx;
+ }
+ }
+
+ if (n_bytes_read > 0) {
+ int l_c_m;
+ size_t bytes_to_write;
+
+ l_c_m = get_lcm();
+
+ /* Make bytes_to_write the smallest multiple of l_c_m that
+ is at least as large as n_bytes_read. */
+ bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m);
+
+ memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read);
+ write_block(current_offset, bytes_to_write,
+ block[!idx], block[idx]);
+ current_offset += n_bytes_read;
+ }
+
+ format_address(current_offset, '\n');
+
+ if (limit_bytes_to_format && current_offset >= end_offset)
+ check_and_close();
+
+ free(block[0]);
+}
+
+/* Read a single byte into *C from the concatenation of the input files
+ named in the global array FILE_LIST. On the first call to this
+ function, the global variable IN_STREAM is expected to be an open
+ stream associated with the input file INPUT_FILENAME. If IN_STREAM
+ is at end-of-file, close it and update the global variables IN_STREAM
+ and INPUT_FILENAME so they correspond to the next file in the list.
+ Then try to read a byte from the newly opened file. Repeat if
+ necessary until EOF is reached for the last file in FILE_LIST, then
+ set *C to EOF and return. Subsequent calls do likewise. */
+
+static void
+read_char(int *c)
+{
+ while (in_stream) { /* !EOF */
+ *c = fgetc(in_stream);
+ if (*c != EOF)
+ return;
+ check_and_close();
+ open_next_file();
+ }
+ *c = EOF;
+}
+
+/* Read N bytes into BLOCK from the concatenation of the input files
+ named in the global array FILE_LIST. On the first call to this
+ function, the global variable IN_STREAM is expected to be an open
+ stream associated with the input file INPUT_FILENAME. If all N
+ bytes cannot be read from IN_STREAM, close IN_STREAM and update
+ the global variables IN_STREAM and INPUT_FILENAME. Then try to
+ read the remaining bytes from the newly opened file. Repeat if
+ necessary until EOF is reached for the last file in FILE_LIST.
+ On subsequent calls, don't modify BLOCK and return zero. Set
+ *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs,
+ it will be detected through ferror when the stream is about to be
+ closed. If there is an error, give a message but continue reading
+ as usual and return nonzero. Otherwise return zero. */
+
+/* STRINGS mode. Find each "string constant" in the input.
+ A string constant is a run of at least 'string_min' ASCII
+ graphic (or formatting) characters terminated by a null.
+ Based on a function written by Richard Stallman for a
+ traditional version of od. */
+
+static void
+dump_strings(off_t address, off_t end_offset)
+{
+ size_t bufsize = MAX(100, string_min);
+ char *buf = xmalloc(bufsize);
+
+ while (1) {
+ size_t i;
+ int c;
+
+ /* See if the next 'string_min' chars are all printing chars. */
+ tryline:
+ if (limit_bytes_to_format && (end_offset - string_min <= address))
+ break;
+ i = 0;
+ while (!limit_bytes_to_format || address < end_offset) {
+ if (i == bufsize) {
+ bufsize += bufsize/8;
+ buf = xrealloc(buf, bufsize);
+ }
+ read_char(&c);
+ if (c < 0) { /* EOF */
+ free(buf);
+ return;
+ }
+ address++;
+ if (!c)
+ break;
+ if (!ISPRINT(c))
+ goto tryline; /* It isn't; give up on this string. */
+ buf[i++] = c; /* String continues; store it all. */
+ }
+
+ if (i < string_min) /* Too short! */
+ goto tryline;
+
+ /* If we get here, the string is all printable and NUL-terminated,
+ * so print it. It is all in 'buf' and 'i' is its length. */
+ buf[i] = 0;
+ format_address(address - i - 1, ' ');
+
+ for (i = 0; (c = buf[i]); i++) {
+ switch (c) {
+ case '\007': fputs("\\a", stdout); break;
+ case '\b': fputs("\\b", stdout); break;
+ case '\f': fputs("\\f", stdout); break;
+ case '\n': fputs("\\n", stdout); break;
+ case '\r': fputs("\\r", stdout); break;
+ case '\t': fputs("\\t", stdout); break;
+ case '\v': fputs("\\v", stdout); break;
+ default: putchar(c);
+ }
+ }
+ putchar('\n');
+ }
+
+ /* We reach this point only if we search through
+ (max_bytes_to_format - string_min) bytes before reaching EOF. */
+ free(buf);
+
+ check_and_close();
+}
+
+int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int od_main(int argc, char **argv)
+{
+ static const struct suffix_mult bkm[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "m", 1024*1024 },
+ { }
+ };
+ enum {
+ OPT_A = 1 << 0,
+ OPT_N = 1 << 1,
+ OPT_a = 1 << 2,
+ OPT_b = 1 << 3,
+ OPT_c = 1 << 4,
+ OPT_d = 1 << 5,
+ OPT_f = 1 << 6,
+ OPT_h = 1 << 7,
+ OPT_i = 1 << 8,
+ OPT_j = 1 << 9,
+ OPT_l = 1 << 10,
+ OPT_o = 1 << 11,
+ OPT_t = 1 << 12,
+ OPT_v = 1 << 13,
+ OPT_x = 1 << 14,
+ OPT_s = 1 << 15,
+ OPT_S = 1 << 16,
+ OPT_w = 1 << 17,
+ OPT_traditional = (1 << 18) * ENABLE_GETOPT_LONG,
+ };
+#if ENABLE_GETOPT_LONG
+ static const char od_longopts[] ALIGN1 =
+ "skip-bytes\0" Required_argument "j"
+ "address-radix\0" Required_argument "A"
+ "read-bytes\0" Required_argument "N"
+ "format\0" Required_argument "t"
+ "output-duplicates\0" No_argument "v"
+ "strings\0" Optional_argument "S"
+ "width\0" Optional_argument "w"
+ "traditional\0" No_argument "\xff"
+ ;
+#endif
+ char *str_A, *str_N, *str_j, *str_S;
+ llist_t *lst_t = NULL;
+ unsigned opt;
+ int l_c_m;
+ /* The old-style 'pseudo starting address' to be printed in parentheses
+ after any true address. */
+ off_t pseudo_start = pseudo_start; // for gcc
+ /* The number of input bytes to skip before formatting and writing. */
+ off_t n_bytes_to_skip = 0;
+ /* The offset of the first byte after the last byte to be formatted. */
+ off_t end_offset = 0;
+ /* The maximum number of bytes that will be formatted. */
+ off_t max_bytes_to_format = 0;
+
+ spec = NULL;
+ format_address = format_address_std;
+ address_base_char = 'o';
+ address_pad_len_char = '7';
+ /* flag_dump_strings = 0; - already is */
+
+ /* Parse command line */
+ opt_complementary = "w+:t::"; /* -w N, -t is a list */
+#if ENABLE_GETOPT_LONG
+ applet_long_options = od_longopts;
+#endif
+ opt = getopt32(argv, "A:N:abcdfhij:lot:vxsS:"
+ "w::", // -w with optional param
+ // -S was -s and also had optional parameter
+ // but in coreutils 6.3 it was renamed and now has
+ // _mandatory_ parameter
+ &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block);
+ argc -= optind;
+ argv += optind;
+ if (opt & OPT_A) {
+ static const char doxn[] ALIGN1 = "doxn";
+ static const char doxn_address_base_char[] ALIGN1 = {
+ 'u', 'o', 'x', /* '?' fourth one is not important */
+ };
+ static const uint8_t doxn_address_pad_len_char[] ALIGN1 = {
+ '7', '7', '6', /* '?' */
+ };
+ char *p;
+ int pos;
+ p = strchr(doxn, str_A[0]);
+ if (!p)
+ bb_error_msg_and_die("bad output address radix "
+ "'%c' (must be [doxn])", str_A[0]);
+ pos = p - doxn;
+ if (pos == 3) format_address = format_address_none;
+ address_base_char = doxn_address_base_char[pos];
+ address_pad_len_char = doxn_address_pad_len_char[pos];
+ }
+ if (opt & OPT_N) {
+ limit_bytes_to_format = 1;
+ max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm);
+ }
+ if (opt & OPT_a) decode_format_string("a");
+ if (opt & OPT_b) decode_format_string("oC");
+ if (opt & OPT_c) decode_format_string("c");
+ if (opt & OPT_d) decode_format_string("u2");
+ if (opt & OPT_f) decode_format_string("fF");
+ if (opt & OPT_h) decode_format_string("x2");
+ if (opt & OPT_i) decode_format_string("d2");
+ if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm);
+ if (opt & OPT_l) decode_format_string("d4");
+ if (opt & OPT_o) decode_format_string("o2");
+ //if (opt & OPT_t)...
+ while (lst_t) {
+ decode_format_string(llist_pop(&lst_t));
+ }
+ if (opt & OPT_v) verbose = 1;
+ if (opt & OPT_x) decode_format_string("x2");
+ if (opt & OPT_s) decode_format_string("d2");
+ if (opt & OPT_S) {
+ string_min = 3;
+ string_min = xstrtou_sfx(str_S, 0, bkm);
+ flag_dump_strings = 1;
+ }
+ //if (opt & OPT_w)...
+ //if (opt & OPT_traditional)...
+
+ if (flag_dump_strings && n_specs > 0)
+ bb_error_msg_and_die("no type may be specified when dumping strings");
+
+ /* If the --traditional option is used, there may be from
+ * 0 to 3 remaining command line arguments; handle each case
+ * separately.
+ * od [file] [[+]offset[.][b] [[+]label[.][b]]]
+ * The offset and pseudo_start have the same syntax.
+ *
+ * FIXME: POSIX 1003.1-2001 with XSI requires support for the
+ * traditional syntax even if --traditional is not given. */
+
+#if ENABLE_GETOPT_LONG
+ if (opt & OPT_traditional) {
+ off_t o1, o2;
+
+ if (argc == 1) {
+ if (parse_old_offset(argv[0], &o1)) {
+ n_bytes_to_skip = o1;
+ --argc;
+ ++argv;
+ }
+ } else if (argc == 2) {
+ if (parse_old_offset(argv[0], &o1)
+ && parse_old_offset(argv[1], &o2)
+ ) {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = 1;
+ pseudo_start = o2;
+ argv += 2;
+ argc -= 2;
+ } else if (parse_old_offset(argv[1], &o2)) {
+ n_bytes_to_skip = o2;
+ --argc;
+ argv[1] = argv[0];
+ ++argv;
+ } else {
+ bb_error_msg_and_die("invalid second operand "
+ "in compatibility mode '%s'", argv[1]);
+ }
+ } else if (argc == 3) {
+ if (parse_old_offset(argv[1], &o1)
+ && parse_old_offset(argv[2], &o2)
+ ) {
+ n_bytes_to_skip = o1;
+ flag_pseudo_start = 1;
+ pseudo_start = o2;
+ argv[2] = argv[0];
+ argv += 2;
+ argc -= 2;
+ } else {
+ bb_error_msg_and_die("in compatibility mode "
+ "the last two arguments must be offsets");
+ }
+ } else if (argc > 3) {
+ bb_error_msg_and_die("compatibility mode supports "
+ "at most three arguments");
+ }
+
+ if (flag_pseudo_start) {
+ if (format_address == format_address_none) {
+ address_base_char = 'o';
+ address_pad_len_char = '7';
+ format_address = format_address_paren;
+ } else
+ format_address = format_address_label;
+ }
+ }
+#endif
+
+ if (limit_bytes_to_format) {
+ end_offset = n_bytes_to_skip + max_bytes_to_format;
+ if (end_offset < n_bytes_to_skip)
+ bb_error_msg_and_die("skip-bytes + read-bytes is too large");
+ }
+
+ if (n_specs == 0) {
+ decode_format_string("o2");
+ n_specs = 1;
+ }
+
+ /* If no files were listed on the command line,
+ set the global pointer FILE_LIST so that it
+ references the null-terminated list of one name: "-". */
+ file_list = bb_argv_dash;
+ if (argc > 0) {
+ /* Set the global pointer FILE_LIST so that it
+ references the first file-argument on the command-line. */
+ file_list = (char const *const *) argv;
+ }
+
+ /* open the first input file */
+ open_next_file();
+ /* skip over any unwanted header bytes */
+ skip(n_bytes_to_skip);
+ if (!in_stream)
+ return EXIT_FAILURE;
+
+ pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0);
+
+ /* Compute output block length. */
+ l_c_m = get_lcm();
+
+ if (opt & OPT_w) { /* -w: width */
+ if (!bytes_per_block || bytes_per_block % l_c_m != 0) {
+ bb_error_msg("warning: invalid width %u; using %d instead",
+ (unsigned)bytes_per_block, l_c_m);
+ bytes_per_block = l_c_m;
+ }
+ } else {
+ bytes_per_block = l_c_m;
+ if (l_c_m < DEFAULT_BYTES_PER_BLOCK)
+ bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m;
+ }
+
+#ifdef DEBUG
+ for (i = 0; i < n_specs; i++) {
+ printf("%d: fmt=\"%s\" width=%d\n",
+ i, spec[i].fmt_string, width_bytes[spec[i].size]);
+ }
+#endif
+
+ if (flag_dump_strings)
+ dump_strings(n_bytes_to_skip, end_offset);
+ else
+ dump(n_bytes_to_skip, end_offset);
+
+ if (fclose(stdin) == EOF)
+ bb_perror_msg_and_die(bb_msg_standard_input);
+
+ return ioerror;
+}
diff --git a/release/src/router/busybox/coreutils/printenv.c b/release/src/router/busybox/coreutils/printenv.c
new file mode 100644
index 00000000..2430f3a1
--- /dev/null
+++ b/release/src/router/busybox/coreutils/printenv.c
@@ -0,0 +1,37 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * printenv implementation for busybox
+ *
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int printenv_main(int argc UNUSED_PARAM, char **argv)
+{
+ int exit_code = EXIT_SUCCESS;
+
+ /* no variables specified, show whole env */
+ if (!argv[1]) {
+ int e = 0;
+ while (environ[e])
+ puts(environ[e++]);
+ } else {
+ /* search for specified variables and print them out if found */
+ char *arg, *env;
+
+ while ((arg = *++argv) != NULL) {
+ env = getenv(arg);
+ if (env)
+ puts(env);
+ else
+ exit_code = EXIT_FAILURE;
+ }
+ }
+
+ fflush_stdout_and_exit(exit_code);
+}
diff --git a/release/src/router/busybox/coreutils/printf.c b/release/src/router/busybox/coreutils/printf.c
index 28f8aa45..0b004eae 100644
--- a/release/src/router/busybox/coreutils/printf.c
+++ b/release/src/router/busybox/coreutils/printf.c
@@ -1,20 +1,11 @@
/* vi: set sw=4 ts=4: */
/* printf - format and print data
- Copyright (C) 90, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ Copyright 1999 Dave Cinege
+ Portions copyright (C) 1990-1996 Free Software Foundation, Inc.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+*/
/* Usage: printf format [argument...]
@@ -39,138 +30,231 @@
%b = print an argument string, interpreting backslash escapes
- The `format' argument is re-used as many times as necessary
+ The 'format' argument is re-used as many times as necessary
to convert all of the given arguments.
- David MacKenzie <djm@gnu.ai.mit.edu> */
-
+ David MacKenzie <djm@gnu.ai.mit.edu>
+*/
// 19990508 Busy Boxed! Dave Cinege
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <assert.h>
-#include "busybox.h"
-
-
-#ifndef S_IFMT
-static const int S_IFMT = 0170000;
-#endif
-#if !defined(S_ISBLK) && defined(S_IFBLK)
-# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
-#endif
-#if !defined(S_ISCHR) && defined(S_IFCHR)
-# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
-#endif
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#endif
-#if !defined(S_ISREG) && defined(S_IFREG)
-# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
-#endif
-#if !defined(S_ISFIFO) && defined(S_IFIFO)
-# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
-#endif
-#if !defined(S_ISLNK) && defined(S_IFLNK)
-# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
-#endif
-#if !defined(S_ISSOCK) && defined(S_IFSOCK)
-# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
-#endif
-#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
-# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
-# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
-#endif
-#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
-# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
-#endif
-
-#define IN_CTYPE_DOMAIN(c) 1
-
-#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
-#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
-#define ISDIGIT(c) (((unsigned char) (c)) - '0' <= 9)
-
-#define isodigit(c) ((c) >= '0' && (c) <= '7')
-#define hextobin(c) ((c)>='a'&&(c)<='f' ? (c)-'a'+10 : (c)>='A'&&(c)<='F' ? (c)-'A'+10 : (c)-'0')
-#define octtobin(c) ((c) - '0')
-
-static double xstrtod __P((char *s));
-static int print_esc __P((char *escstart));
-static int print_formatted __P((char *format, int argc, char **argv));
-static long xstrtol __P((char *s));
-static unsigned long xstrtoul __P((char *s));
-static void print_direc __P( (char *start, size_t length,
- int field_width, int precision, char *argument));
-static void print_esc_char __P((int c));
-static void print_esc_string __P((char *str));
-
-/* The value to return to the calling program. */
-static int exit_status;
-
-int printf_main(int argc, char **argv)
+#include "libbb.h"
+
+/* A note on bad input: neither bash 3.2 nor coreutils 6.10 stop on it.
+ * They report it:
+ * bash: printf: XXX: invalid number
+ * printf: XXX: expected a numeric value
+ * bash: printf: 123XXX: invalid number
+ * printf: 123XXX: value not completely converted
+ * but then they use 0 (or partially converted numeric prefix) as a value
+ * and continue. They exit with 1 in this case.
+ * Both accept insane field width/precision (e.g. %9999999999.9999999999d).
+ * Both print error message and assume 0 if %*.*f width/precision is "bad"
+ * (but negative numbers are not "bad").
+ * Both accept negative numbers for %u specifier.
+ *
+ * We try to be compatible. We are not compatible here:
+ * - we do not accept -NUM for %u
+ * - exit code is 0 even if "invalid number" was seen (FIXME)
+ * See "if (errno)" checks in the code below.
+ */
+
+typedef void FAST_FUNC (*converter)(const char *arg, void *result);
+
+static int multiconvert(const char *arg, void *result, converter convert)
{
- char *format;
- int args_used;
+ if (*arg == '"' || *arg == '\'') {
+ arg = utoa((unsigned char)arg[1]);
+ }
+ errno = 0;
+ convert(arg, result);
+ if (errno) {
+ bb_error_msg("%s: invalid number", arg);
+ return 1;
+ }
+ return 0;
+}
- exit_status = 0;
- if (argc <= 1 || **(argv + 1) == '-') {
- bb_show_usage();
+static void FAST_FUNC conv_strtoull(const char *arg, void *result)
+{
+ *(unsigned long long*)result = bb_strtoull(arg, NULL, 0);
+}
+static void FAST_FUNC conv_strtoll(const char *arg, void *result)
+{
+ *(long long*)result = bb_strtoll(arg, NULL, 0);
+}
+static void FAST_FUNC conv_strtod(const char *arg, void *result)
+{
+ char *end;
+ /* Well, this one allows leading whitespace... so what? */
+ /* What I like much less is that "-" accepted too! :( */
+ *(double*)result = strtod(arg, &end);
+ if (end[0]) {
+ errno = ERANGE;
+ *(double*)result = 0;
}
+}
- format = argv[1];
- argc -= 2;
- argv += 2;
+/* Callers should check errno to detect errors */
+static unsigned long long my_xstrtoull(const char *arg)
+{
+ unsigned long long result;
+ if (multiconvert(arg, &result, conv_strtoull))
+ result = 0;
+ return result;
+}
+static long long my_xstrtoll(const char *arg)
+{
+ long long result;
+ if (multiconvert(arg, &result, conv_strtoll))
+ result = 0;
+ return result;
+}
+static double my_xstrtod(const char *arg)
+{
+ double result;
+ multiconvert(arg, &result, conv_strtod);
+ return result;
+}
- do {
- args_used = print_formatted(format, argc, argv);
- argc -= args_used;
- argv += args_used;
+static void print_esc_string(char *str)
+{
+ while (*str) {
+ if (*str == '\\') {
+ str++;
+ bb_putchar(bb_process_escape_sequence((const char **)&str));
+ } else {
+ bb_putchar(*str);
+ str++;
+ }
}
- while (args_used > 0 && argc > 0);
+}
-/*
- if (argc > 0)
- fprintf(stderr, "excess args ignored");
-*/
+static void print_direc(char *format, unsigned fmt_length,
+ int field_width, int precision,
+ const char *argument)
+{
+ long long llv;
+ double dv;
+ char saved;
+ char *have_prec, *have_width;
+
+ saved = format[fmt_length];
+ format[fmt_length] = '\0';
+
+ have_prec = strstr(format, ".*");
+ have_width = strchr(format, '*');
+ if (have_width - 1 == have_prec)
+ have_width = NULL;
+
+ switch (format[fmt_length - 1]) {
+ case 'c':
+ printf(format, *argument);
+ break;
+ case 'd':
+ case 'i':
+ llv = my_xstrtoll(argument);
+ print_long:
+ /* if (errno) return; - see comment at the top */
+ if (!have_width) {
+ if (!have_prec)
+ printf(format, llv);
+ else
+ printf(format, precision, llv);
+ } else {
+ if (!have_prec)
+ printf(format, field_width, llv);
+ else
+ printf(format, field_width, precision, llv);
+ }
+ break;
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ llv = my_xstrtoull(argument);
+ /* cheat: unsigned long and long have same width, so... */
+ goto print_long;
+ case 's':
+ /* Are char* and long long the same? */
+ if (sizeof(argument) == sizeof(llv)) {
+ llv = (long long)(ptrdiff_t)argument;
+ goto print_long;
+ } else {
+ /* Hope compiler will optimize it out by moving call
+ * instruction after the ifs... */
+ if (!have_width) {
+ if (!have_prec)
+ printf(format, argument, /*unused:*/ argument, argument);
+ else
+ printf(format, precision, argument, /*unused:*/ argument);
+ } else {
+ if (!have_prec)
+ printf(format, field_width, argument, /*unused:*/ argument);
+ else
+ printf(format, field_width, precision, argument);
+ }
+ break;
+ }
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ dv = my_xstrtod(argument);
+ /* if (errno) return; */
+ if (!have_width) {
+ if (!have_prec)
+ printf(format, dv);
+ else
+ printf(format, precision, dv);
+ } else {
+ if (!have_prec)
+ printf(format, field_width, dv);
+ else
+ printf(format, field_width, precision, dv);
+ }
+ break;
+ } /* switch */
- return(exit_status);
+ format[fmt_length] = saved;
}
-/* Print the text in FORMAT, using ARGV (with ARGC elements) for
- arguments to any `%' directives.
- Return the number of elements of ARGV used. */
+/* Handle params for "%*.*f". Negative numbers are ok (compat). */
+static int get_width_prec(const char *str)
+{
+ int v = bb_strtoi(str, NULL, 10);
+ if (errno) {
+ bb_error_msg("%s: invalid number", str);
+ v = 0;
+ }
+ return v;
+}
-static int print_formatted(char *format, int argc, char **argv)
+/* Print the text in FORMAT, using ARGV for arguments to any '%' directives.
+ Return advanced ARGV. */
+static char **print_formatted(char *f, char **argv)
{
- int save_argc = argc; /* Preserve original value. */
- char *f; /* Pointer into `format'. */
- char *direc_start; /* Start of % directive. */
- size_t direc_length; /* Length of % directive. */
- int field_width; /* Arg to first '*', or -1 if none. */
- int precision; /* Arg to second '*', or -1 if none. */
-
- for (f = format; *f; ++f) {
+ char *direc_start; /* Start of % directive. */
+ unsigned direc_length; /* Length of % directive. */
+ int field_width; /* Arg to first '*' */
+ int precision; /* Arg to second '*' */
+ char **saved_argv = argv;
+
+ for (; *f; ++f) {
switch (*f) {
case '%':
direc_start = f++;
direc_length = 1;
- field_width = precision = -1;
+ field_width = precision = 0;
if (*f == '%') {
- putchar('%');
+ bb_putchar('%');
break;
}
if (*f == 'b') {
- if (argc > 0) {
+ if (*argv) {
print_esc_string(*argv);
++argv;
- --argc;
}
break;
}
@@ -181,272 +265,134 @@ static int print_formatted(char *format, int argc, char **argv)
if (*f == '*') {
++f;
++direc_length;
- if (argc > 0) {
- field_width = xstrtoul(*argv);
- ++argv;
- --argc;
- } else
- field_width = 0;
- } else
- while (ISDIGIT(*f)) {
+ if (*argv)
+ field_width = get_width_prec(*argv++);
+ } else {
+ while (isdigit(*f)) {
++f;
++direc_length;
}
+ }
if (*f == '.') {
++f;
++direc_length;
if (*f == '*') {
++f;
++direc_length;
- if (argc > 0) {
- precision = xstrtoul(*argv);
- ++argv;
- --argc;
- } else
- precision = 0;
- } else
- while (ISDIGIT(*f)) {
+ if (*argv)
+ precision = get_width_prec(*argv++);
+ } else {
+ while (isdigit(*f)) {
++f;
++direc_length;
}
+ }
}
- if (*f == 'l' || *f == 'L' || *f == 'h') {
- ++f;
+
+ /* Remove "lLhz" size modifiers, repeatedly.
+ * bash does not like "%lld", but coreutils
+ * would happily take even "%Llllhhzhhzd"!
+ * We will be permissive like coreutils */
+ while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') {
+ overlapping_strcpy(f, f + 1);
+ }
+ /* Add "ll" if integer modifier, then print */
+ {
+ static const char format_chars[] ALIGN1 = "diouxXfeEgGcs";
+ char *p = strchr(format_chars, *f);
+ /* needed - try "printf %" without it */
+ if (p == NULL) {
+ bb_error_msg("%s: invalid format", direc_start);
+ /* causes main() to exit with error */
+ return saved_argv - 1;
+ }
++direc_length;
+ if (p - format_chars <= 5) {
+ /* it is one of "diouxX" */
+ p = xmalloc(direc_length + 3);
+ memcpy(p, direc_start, direc_length);
+ p[direc_length + 1] = p[direc_length - 1];
+ p[direc_length - 1] = 'l';
+ p[direc_length] = 'l';
+ //bb_error_msg("<%s>", p);
+ direc_length += 2;
+ direc_start = p;
+ } else {
+ p = NULL;
+ }
+ if (*argv) {
+ print_direc(direc_start, direc_length, field_width,
+ precision, *argv);
+ ++argv;
+ } else {
+ print_direc(direc_start, direc_length, field_width,
+ precision, "");
+ }
+ free(p);
}
- /*
- if (!strchr ("diouxXfeEgGcs", *f))
- fprintf(stderr, "%%%c: invalid directive", *f);
- */
- ++direc_length;
- if (argc > 0) {
- print_direc(direc_start, direc_length, field_width,
- precision, *argv);
- ++argv;
- --argc;
- } else
- print_direc(direc_start, direc_length, field_width,
- precision, "");
break;
-
case '\\':
- f += print_esc(f);
+ if (*++f == 'c') {
+ return saved_argv; /* causes main() to exit */
+ }
+ bb_putchar(bb_process_escape_sequence((const char **)&f));
+ f--;
break;
-
default:
- putchar(*f);
+ bb_putchar(*f);
}
}
- return save_argc - argc;
+ return argv;
}
-/* Print a \ escape sequence starting at ESCSTART.
- Return the number of characters in the escape sequence
- besides the backslash. */
-
-static int print_esc(char *escstart)
+int printf_main(int argc UNUSED_PARAM, char **argv)
{
- register char *p = escstart + 1;
- int esc_value = 0; /* Value of \nnn escape. */
- int esc_length; /* Length of \nnn escape. */
-
- /* \0ooo and \xhhh escapes have maximum length of 3 chars. */
- if (*p == 'x') {
- for (esc_length = 0, ++p;
- esc_length < 3 && ISXDIGIT(*p); ++esc_length, ++p)
- esc_value = esc_value * 16 + hextobin(*p);
-/* if (esc_length == 0)
- fprintf(stderr, "missing hex in esc");
-*/
- putchar(esc_value);
- } else if (*p == '0') {
- for (esc_length = 0, ++p;
- esc_length < 3 && isodigit(*p); ++esc_length, ++p)
- esc_value = esc_value * 8 + octtobin(*p);
- putchar(esc_value);
- } else if (strchr("\"\\abcfnrtv", *p))
- print_esc_char(*p++);
-/* else
- fprintf(stderr, "\\%c: invalid esc", *p);
-*/
- return p - escstart - 1;
-}
-
-/* Output a single-character \ escape. */
-
-static void print_esc_char(int c)
-{
- switch (c) {
- case 'a': /* Alert. */
- putchar(7);
- break;
- case 'b': /* Backspace. */
- putchar(8);
- break;
- case 'c': /* Cancel the rest of the output. */
- exit(0);
- break;
- case 'f': /* Form feed. */
- putchar(12);
- break;
- case 'n': /* New line. */
- putchar(10);
- break;
- case 'r': /* Carriage return. */
- putchar(13);
- break;
- case 't': /* Horizontal tab. */
- putchar(9);
- break;
- case 'v': /* Vertical tab. */
- putchar(11);
- break;
- default:
- putchar(c);
- break;
- }
-}
-
-/* Print string STR, evaluating \ escapes. */
-
-static void print_esc_string(char *str)
-{
- for (; *str; str++)
- if (*str == '\\')
- str += print_esc(str);
- else
- putchar(*str);
-}
-
-static void
-print_direc(char *start, size_t length, int field_width, int precision,
- char *argument)
-{
- char *p; /* Null-terminated copy of % directive. */
-
- p = xmalloc((unsigned) (length + 1));
- strncpy(p, start, length);
- p[length] = 0;
-
- switch (p[length - 1]) {
- case 'd':
- case 'i':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtol(argument));
- else
- printf(p, precision, xstrtol(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtol(argument));
- else
- printf(p, field_width, precision, xstrtol(argument));
- }
- break;
-
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtoul(argument));
- else
- printf(p, precision, xstrtoul(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtoul(argument));
- else
- printf(p, field_width, precision, xstrtoul(argument));
- }
- break;
-
- case 'f':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, xstrtod(argument));
- else
- printf(p, precision, xstrtod(argument));
- } else {
- if (precision < 0)
- printf(p, field_width, xstrtod(argument));
- else
- printf(p, field_width, precision, xstrtod(argument));
- }
- break;
-
- case 'c':
- printf(p, *argument);
- break;
-
- case 's':
- if (field_width < 0) {
- if (precision < 0)
- printf(p, argument);
- else
- printf(p, precision, argument);
- } else {
- if (precision < 0)
- printf(p, field_width, argument);
- else
- printf(p, field_width, precision, argument);
+ char *format;
+ char **argv2;
+
+ /* We must check that stdout is not closed.
+ * The reason for this is highly non-obvious.
+ * printf_main is used from shell.
+ * Shell must correctly handle 'printf "%s" foo'
+ * if stdout is closed. With stdio, output gets shoveled into
+ * stdout buffer, and even fflush cannot clear it out. It seems that
+ * even if libc receives EBADF on write attempts, it feels determined
+ * to output data no matter what. So it will try later,
+ * and possibly will clobber future output. Not good. */
+// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR?
+ if (fcntl(1, F_GETFL) == -1)
+ return 1; /* match coreutils 6.10 (sans error msg to stderr) */
+ //if (dup2(1, 1) != 1) - old way
+ // return 1;
+
+ /* bash builtin errors out on "printf '-%s-\n' foo",
+ * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
+ * We will mimic coreutils. */
+ if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2])
+ argv++;
+ if (!argv[1]) {
+ if (ENABLE_ASH_BUILTIN_PRINTF
+ && applet_name[0] != 'p'
+ ) {
+ bb_error_msg("usage: printf FORMAT [ARGUMENT...]");
+ return 2; /* bash compat */
}
- break;
+ bb_show_usage();
}
- free(p);
-}
-
-static unsigned long xstrtoul(char *arg)
-{
- unsigned long result;
- char *endptr;
- //int errno_save = errno;
-
- assert(arg!=NULL);
-
- errno = 0;
- result = strtoul(arg, &endptr, 10);
- if (errno != 0 || *endptr!='\0' || endptr==arg)
- fprintf(stderr, "%s", arg);
- //errno = errno_save;
- return result;
-}
-
-static long xstrtol(char *arg)
-{
- long result;
- char *endptr;
- //int errno_save = errno;
-
- assert(arg!=NULL);
-
- errno = 0;
- result = strtoul(arg, &endptr, 10);
- if (errno != 0 || *endptr!='\0' || endptr==arg)
- fprintf(stderr, "%s", arg);
- //errno = errno_save;
- return result;
-}
+ format = argv[1];
+ argv2 = argv + 2;
-static double xstrtod(char *arg)
-{
- double result;
- char *endptr;
- //int errno_save = errno;
+ do {
+ argv = argv2;
+ argv2 = print_formatted(format, argv);
+ } while (argv2 > argv && *argv2);
- assert(arg!=NULL);
+ /* coreutils compat (bash doesn't do this):
+ if (*argv)
+ fprintf(stderr, "excess args ignored");
+ */
- errno = 0;
- result = strtod(arg, &endptr);
- if (errno != 0 || *endptr!='\0' || endptr==arg)
- fprintf(stderr, "%s", arg);
- //errno = errno_save;
- return result;
+ return (argv2 < argv); /* if true, print_formatted errored out */
}
-
diff --git a/release/src/router/busybox/coreutils/pwd.c b/release/src/router/busybox/coreutils/pwd.c
index 7e0dc056..57953d24 100644
--- a/release/src/router/busybox/coreutils/pwd.c
+++ b/release/src/router/busybox/coreutils/pwd.c
@@ -4,33 +4,23 @@
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int pwd_main(int argc, char **argv)
+int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int pwd_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
char *buf;
- if ((buf = xgetcwd(NULL)) != NULL) {
+ buf = xrealloc_getcwd_or_warn(NULL);
+ if (buf != NULL) {
puts(buf);
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ free(buf);
+ return fflush(stdout);
}
return EXIT_FAILURE;
diff --git a/release/src/router/busybox/coreutils/readlink.c b/release/src/router/busybox/coreutils/readlink.c
new file mode 100644
index 00000000..bcf352e7
--- /dev/null
+++ b/release/src/router/busybox/coreutils/readlink.c
@@ -0,0 +1,72 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini readlink implementation for busybox
+ *
+ * Copyright (C) 2000,2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ *
+ * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+/*
+ * # readlink --version
+ * readlink (GNU coreutils) 6.10
+ * # readlink --help
+ * -f, --canonicalize
+ * canonicalize by following every symlink in
+ * every component of the given name recursively;
+ * all but the last component must exist
+ * -e, --canonicalize-existing
+ * canonicalize by following every symlink in
+ * every component of the given name recursively,
+ * all components must exist
+ * -m, --canonicalize-missing
+ * canonicalize by following every symlink in
+ * every component of the given name recursively,
+ * without requirements on components existence
+ * -n, --no-newline do not output the trailing newline
+ * -q, --quiet, -s, --silent suppress most error messages
+ * -v, --verbose report error messages
+ *
+ * bbox supports: -f -n -v (fully), -q -s (accepts but ignores)
+ */
+
+int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int readlink_main(int argc UNUSED_PARAM, char **argv)
+{
+ char *buf;
+ char *fname;
+ char pathbuf[PATH_MAX];
+
+ USE_FEATURE_READLINK_FOLLOW(
+ unsigned opt;
+ /* We need exactly one non-option argument. */
+ opt_complementary = "=1";
+ opt = getopt32(argv, "fnvsq");
+ fname = argv[optind];
+ )
+ SKIP_FEATURE_READLINK_FOLLOW(
+ const unsigned opt = 0;
+ if (argc != 2) bb_show_usage();
+ fname = argv[1];
+ )
+
+ /* compat: coreutils readlink reports errors silently via exit code */
+ if (!(opt & 4)) /* not -v */
+ logmode = LOGMODE_NONE;
+
+ if (opt & 1) { /* -f */
+ buf = realpath(fname, pathbuf);
+ } else {
+ buf = xmalloc_readlink_or_warn(fname);
+ }
+
+ if (!buf)
+ return EXIT_FAILURE;
+ printf((opt & 2) ? "%s" : "%s\n", buf);
+
+ if (ENABLE_FEATURE_CLEAN_UP && !opt)
+ free(buf);
+
+ fflush_stdout_and_exit(EXIT_SUCCESS);
+}
diff --git a/release/src/router/busybox/coreutils/realpath.c b/release/src/router/busybox/coreutils/realpath.c
index ec98221a..28906ba5 100644
--- a/release/src/router/busybox/coreutils/realpath.c
+++ b/release/src/router/busybox/coreutils/realpath.c
@@ -1,54 +1,46 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
+/* vi: set sw=4 ts=4: */
/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
*
* Now does proper error checking on output and returns a failure exit code
- * if one or more paths can not be resolved.
+ * if one or more paths cannot be resolved.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <limits.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
-int realpath_main(int argc, char **argv)
+int realpath_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int realpath_main(int argc UNUSED_PARAM, char **argv)
{
int retval = EXIT_SUCCESS;
+#if PATH_MAX > (BUFSIZ+1)
RESERVE_CONFIG_BUFFER(resolved_path, PATH_MAX);
+# define resolved_path_MUST_FREE 1
+#else
+#define resolved_path bb_common_bufsiz1
+# define resolved_path_MUST_FREE 0
+#endif
- if (--argc == 0) {
+ if (!*++argv) {
bb_show_usage();
}
do {
- argv++;
if (realpath(*argv, resolved_path) != NULL) {
puts(resolved_path);
} else {
retval = EXIT_FAILURE;
- bb_perror_msg("%s", *argv);
+ bb_simple_perror_msg(*argv);
}
- } while (--argc);
+ } while (*++argv);
-#ifdef CONFIG_FEATURE_CLEAN_UP
+#if ENABLE_FEATURE_CLEAN_UP && resolved_path_MUST_FREE
RELEASE_CONFIG_BUFFER(resolved_path);
#endif
- bb_fflush_stdout_and_exit(retval);
+ fflush_stdout_and_exit(retval);
}
diff --git a/release/src/router/busybox/coreutils/rm.c b/release/src/router/busybox/coreutils/rm.c
index 39609e7b..6b3fbcf2 100644
--- a/release/src/router/busybox/coreutils/rm.c
+++ b/release/src/router/busybox/coreutils/rm.c
@@ -4,21 +4,7 @@
*
* Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
*
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
@@ -29,30 +15,34 @@
* Size reduction.
*/
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int rm_main(int argc, char **argv)
+int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rm_main(int argc UNUSED_PARAM, char **argv)
{
int status = 0;
int flags = 0;
- unsigned long opt;
-
- bb_opt_complementaly = "f-i:i-f";
- opt = bb_getopt_ulflags(argc, argv, "fiRr");
- if(opt & 1)
- flags |= FILEUTILS_FORCE;
- if(opt & 2)
+ unsigned opt;
+
+ opt_complementary = "f-i:i-f";
+ /* -v (verbose) is ignored */
+ opt = getopt32(argv, "fiRrv");
+ argv += optind;
+ if (opt & 1)
+ flags |= FILEUTILS_FORCE;
+ if (opt & 2)
flags |= FILEUTILS_INTERACTIVE;
- if(opt & 12)
+ if (opt & (8|4))
flags |= FILEUTILS_RECUR;
- if (*(argv += optind) != NULL) {
+ if (*argv != NULL) {
do {
- const char *base = bb_get_last_path_component(*argv);
+ const char *base = bb_get_last_path_component_strip(*argv);
- if ((base[0] == '.') && (!base[1] || ((base[1] == '.') && !base[2]))) {
- bb_error_msg("cannot remove `.' or `..'");
+ if (DOT_OR_DOTDOT(base)) {
+ bb_error_msg("cannot remove '.' or '..'");
} else if (remove_file(*argv, flags) >= 0) {
continue;
}
diff --git a/release/src/router/busybox/coreutils/rmdir.c b/release/src/router/busybox/coreutils/rmdir.c
index 3f603717..2450a43a 100644
--- a/release/src/router/busybox/coreutils/rmdir.c
+++ b/release/src/router/busybox/coreutils/rmdir.c
@@ -4,39 +4,37 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */
-#include <stdlib.h>
-#include <unistd.h>
-#include <libgen.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int rmdir_main(int argc, char **argv)
+
+#define PARENTS 0x01
+#define IGNORE_NON_EMPTY 0x02
+
+int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int rmdir_main(int argc UNUSED_PARAM, char **argv)
{
int status = EXIT_SUCCESS;
int flags;
- int do_dot;
char *path;
- flags = bb_getopt_ulflags(argc, argv, "p");
-
+#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS
+ static const char rmdir_longopts[] ALIGN1 =
+ "parents\0" No_argument "p"
+ /* Debian etch: many packages fail to be purged or installed
+ * because they desperately want this option: */
+ "ignore-fail-on-non-empty\0" No_argument "\xff"
+ ;
+ applet_long_options = rmdir_longopts;
+#endif
+ flags = getopt32(argv, "p");
argv += optind;
if (!*argv) {
@@ -46,27 +44,26 @@ extern int rmdir_main(int argc, char **argv)
do {
path = *argv;
- /* Record if the first char was a '.' so we can use dirname later. */
- do_dot = (*path == '.');
-
- do {
+ while (1) {
if (rmdir(path) < 0) {
- bb_perror_msg("`%s'", path); /* Match gnu rmdir msg. */
+#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS
+ if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY)
+ break;
+#endif
+ bb_perror_msg("'%s'", path); /* Match gnu rmdir msg. */
status = EXIT_FAILURE;
- } else if (flags) {
- /* Note: path was not empty or null since rmdir succeeded. */
+ } else if (flags & PARENTS) {
+ /* Note: path was not "" since rmdir succeeded. */
path = dirname(path);
- /* Path is now just the parent component. Note that dirname
- * returns "." if there are no parents. We must distinguish
- * this from the case of the original path starting with '.'.
- */
- if (do_dot || (*path != '.') || path[1]) {
+ /* Path is now just the parent component. Dirname
+ * returns "." if there are no parents.
+ */
+ if (NOT_LONE_CHAR(path, '.')) {
continue;
}
}
break;
- } while (1);
-
+ }
} while (*++argv);
return status;
diff --git a/release/src/router/busybox/coreutils/seq.c b/release/src/router/busybox/coreutils/seq.c
new file mode 100644
index 00000000..4b853c69
--- /dev/null
+++ b/release/src/router/busybox/coreutils/seq.c
@@ -0,0 +1,53 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * seq implementation for busybox
+ *
+ * Copyright (C) 2004, Glenn McGrath
+ *
+ * Licensed under the GPL v2, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
+
+
+int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int seq_main(int argc, char **argv)
+{
+ enum {
+ OPT_w = (1 << 0),
+ OPT_s = (1 << 1),
+ };
+ double last, increment, i;
+ const char *sep, *opt_s = "\n";
+ unsigned opt = getopt32(argv, "+ws:", &opt_s);
+ unsigned width = 0;
+
+ argc -= optind;
+ argv += optind;
+ i = increment = 1;
+ switch (argc) {
+ case 3:
+ increment = atof(argv[1]);
+ case 2:
+ i = atof(*argv);
+ case 1:
+ last = atof(argv[argc-1]);
+ break;
+ default:
+ bb_show_usage();
+ }
+ if (opt & OPT_w) /* Pad to length of start or last */
+ width = MAX(strlen(*argv), strlen(argv[argc-1]));
+
+ /* You should note that this is pos-5.0.91 semantics, -- FK. */
+ sep = "";
+ while ((increment > 0 && i <= last) || (increment < 0 && i >= last)) {
+ printf("%s%0*g", sep, width, i);
+ sep = opt_s;
+ i += increment;
+ }
+ bb_putchar('\n');
+ return fflush(stdout);
+}
diff --git a/release/src/router/busybox/coreutils/sha1sum.c b/release/src/router/busybox/coreutils/sha1sum.c
deleted file mode 100644
index 1148aac1..00000000
--- a/release/src/router/busybox/coreutils/sha1sum.c
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Based on shasum from http://www.netsw.org/crypto/hash/
- * Majorly hacked up to use Dr Brian Gladman's sha1 code
- *
- * Copyright (C) 1999 Scott G. Miller
- * Copyright (C) 2003 Glenn L. McGrath
- * Copyright (C) 2003 Erik Andersen
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <stdint.h>
-#include <endian.h>
-#include <byteswap.h>
-#include "busybox.h"
-
-
-/*
- ---------------------------------------------------------------------------
- Begin Dr. Gladman's sha1 code
- ---------------------------------------------------------------------------
-*/
-
-/*
- ---------------------------------------------------------------------------
- Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
- All rights reserved.
-
- LICENSE TERMS
-
- The free distribution and use of this software in both source and binary
- form is allowed (with or without changes) provided that:
-
- 1. distributions of this source code include the above copyright
- notice, this list of conditions and the following disclaimer;
-
- 2. distributions in binary form include the above copyright
- notice, this list of conditions and the following disclaimer
- in the documentation and/or other associated materials;
-
- 3. the copyright holder's name is not used to endorse products
- built using this software without specific written permission.
-
- ALTERNATIVELY, provided that this notice is retained in full, this product
- may be distributed under the terms of the GNU General Public License (GPL),
- in which case the provisions of the GPL apply INSTEAD OF those given above.
-
- DISCLAIMER
-
- This software is provided 'as is' with no explicit or implied warranties
- in respect of its properties, including, but not limited to, correctness
- and/or fitness for purpose.
- ---------------------------------------------------------------------------
- Issue Date: 10/11/2002
-
- This is a byte oriented version of SHA1 that operates on arrays of bytes
- stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor
-*/
-
-#define SHA1_BLOCK_SIZE 64
-#define SHA1_DIGEST_SIZE 20
-#define SHA1_HASH_SIZE SHA1_DIGEST_SIZE
-#define SHA2_GOOD 0
-#define SHA2_BAD 1
-
-/* type to hold the SHA1 context */
-typedef struct
-{ uint32_t count[2];
- uint32_t hash[5];
- uint32_t wbuf[16];
-} sha1_ctx;
-
-#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n)))
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-# define swap_b32(x) (x)
-#elif defined(bswap_32)
-# define swap_b32(x) bswap_32(x)
-#else
-# define swap_b32(x) ((rotl32((x), 8) & 0x00ff00ff) | (rotl32((x), 24) & 0xff00ff00))
-#endif
-
-#define SHA1_MASK (SHA1_BLOCK_SIZE - 1)
-
-/* reverse byte order in 32-bit words */
-#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
-#define parity(x,y,z) ((x) ^ (y) ^ (z))
-#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
-
-/* A normal version as set out in the FIPS. This version uses */
-/* partial loop unrolling and is optimised for the Pentium 4 */
-#define rnd(f,k) \
- t = a; a = rotl32(a,5) + f(b,c,d) + e + k + w[i]; \
- e = d; d = c; c = rotl32(b, 30); b = t
-
-void sha1_compile(sha1_ctx ctx[1])
-{
- uint32_t w[80], i, a, b, c, d, e, t;
-
- /* note that words are compiled from the buffer into 32-bit */
- /* words in big-endian order so an order reversal is needed */
- /* here on little endian machines */
- for(i = 0; i < SHA1_BLOCK_SIZE / 4; ++i)
- w[i] = swap_b32(ctx->wbuf[i]);
-
- for(i = SHA1_BLOCK_SIZE / 4; i < 80; ++i)
- w[i] = rotl32(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
-
- a = ctx->hash[0];
- b = ctx->hash[1];
- c = ctx->hash[2];
- d = ctx->hash[3];
- e = ctx->hash[4];
-
- for(i = 0; i < 20; ++i)
- {
- rnd(ch, 0x5a827999);
- }
-
- for(i = 20; i < 40; ++i)
- {
- rnd(parity, 0x6ed9eba1);
- }
-
- for(i = 40; i < 60; ++i)
- {
- rnd(maj, 0x8f1bbcdc);
- }
-
- for(i = 60; i < 80; ++i)
- {
- rnd(parity, 0xca62c1d6);
- }
-
- ctx->hash[0] += a;
- ctx->hash[1] += b;
- ctx->hash[2] += c;
- ctx->hash[3] += d;
- ctx->hash[4] += e;
-}
-
-void sha1_begin(sha1_ctx ctx[1])
-{
- ctx->count[0] = ctx->count[1] = 0;
- ctx->hash[0] = 0x67452301;
- ctx->hash[1] = 0xefcdab89;
- ctx->hash[2] = 0x98badcfe;
- ctx->hash[3] = 0x10325476;
- ctx->hash[4] = 0xc3d2e1f0;
-}
-
-/* SHA1 hash data in an array of bytes into hash buffer and call the */
-/* hash_compile function as required. */
-void sha1_hash(const unsigned char data[], unsigned int len, sha1_ctx ctx[1])
-{
- uint32_t pos = (uint32_t)(ctx->count[0] & SHA1_MASK),
- freeb = SHA1_BLOCK_SIZE - pos;
- const unsigned char *sp = data;
-
- if((ctx->count[0] += len) < len)
- ++(ctx->count[1]);
-
- while(len >= freeb) /* tranfer whole blocks while possible */
- {
- memcpy(((unsigned char*)ctx->wbuf) + pos, sp, freeb);
- sp += freeb; len -= freeb; freeb = SHA1_BLOCK_SIZE; pos = 0;
- sha1_compile(ctx);
- }
-
- memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len);
-}
-
-/* SHA1 Final padding and digest calculation */
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-static uint32_t mask[4] =
- { 0x00000000, 0x000000ff, 0x0000ffff, 0x00ffffff };
-static uint32_t bits[4] =
- { 0x00000080, 0x00008000, 0x00800000, 0x80000000 };
-#else
-static uint32_t mask[4] =
- { 0x00000000, 0xff000000, 0xffff0000, 0xffffff00 };
-static uint32_t bits[4] =
- { 0x80000000, 0x00800000, 0x00008000, 0x00000080 };
-#endif
-
-void sha1_end(unsigned char hval[], sha1_ctx ctx[1])
-{
- uint32_t i, cnt = (uint32_t)(ctx->count[0] & SHA1_MASK);
-
- /* mask out the rest of any partial 32-bit word and then set */
- /* the next byte to 0x80. On big-endian machines any bytes in */
- /* the buffer will be at the top end of 32 bit words, on little */
- /* endian machines they will be at the bottom. Hence the AND */
- /* and OR masks above are reversed for little endian systems */
- ctx->wbuf[cnt >> 2] = (ctx->wbuf[cnt >> 2] & mask[cnt & 3]) | bits[cnt & 3];
-
- /* we need 9 or more empty positions, one for the padding byte */
- /* (above) and eight for the length count. If there is not */
- /* enough space pad and empty the buffer */
- if(cnt > SHA1_BLOCK_SIZE - 9)
- {
- if(cnt < 60) ctx->wbuf[15] = 0;
- sha1_compile(ctx);
- cnt = 0;
- }
- else /* compute a word index for the empty buffer positions */
- cnt = (cnt >> 2) + 1;
-
- while(cnt < 14) /* and zero pad all but last two positions */
- ctx->wbuf[cnt++] = 0;
-
- /* assemble the eight byte counter in the buffer in big-endian */
- /* format */
-
- ctx->wbuf[14] = swap_b32((ctx->count[1] << 3) | (ctx->count[0] >> 29));
- ctx->wbuf[15] = swap_b32(ctx->count[0] << 3);
-
- sha1_compile(ctx);
-
- /* extract the hash value as bytes in case the hash buffer is */
- /* misaligned for 32-bit words */
-
- for(i = 0; i < SHA1_DIGEST_SIZE; ++i)
- hval[i] = (unsigned char)(ctx->hash[i >> 2] >> 8 * (~i & 3));
-}
-
-#if 0
-void sha1(unsigned char hval[], const unsigned char data[], unsigned int len)
-{ sha1_ctx cx[1];
-
- sha1_begin(cx); sha1_hash(data, len, cx); sha1_end(hval, cx);
-}
-#endif
-
-/*
- ---------------------------------------------------------------------------
- End of Dr. Gladman's sha1 code
- ---------------------------------------------------------------------------
-*/
-
-/* Using a larger blocksize can make things _much_ faster
- * by avoiding a zillion tiny little reads */
-#define BLOCKSIZE 65536
-/* Ensure that BLOCKSIZE is a multiple of 64. */
-#if BLOCKSIZE % SHA1_BLOCK_SIZE != 0
-# error "BLOCKSIZE not a multiple of 64"
-#endif
-
-static int sha1sum_stream(FILE *stream, unsigned char *hashval)
-{
- int result = 0;
- sha1_ctx cx[1];
- size_t sum, n;
- RESERVE_CONFIG_BUFFER(buffer, BLOCKSIZE + 72);
-
- /* Initialize the computation context. */
- sha1_begin(cx);
-
- /* Iterate over full file contents. */
- while (1)
- {
- /* We read the file in blocks of BLOCKSIZE bytes. One call of the
- computation function processes the whole buffer so that with the
- next round of the loop another block can be read. */
- sum = 0;
-
- /* Read block. Take care for partial reads. */
- while (1)
- {
- n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
- sum += n;
-
- if (sum == BLOCKSIZE)
- break;
-
- if (n == 0) {
- /* Check for the error flag IFF N == 0, so that we don't
- exit the loop after a partial read due to e.g., EAGAIN
- or EWOULDBLOCK. */
- if (feof (stream)) {
- sum = 0;
- goto process_partial_block;
- }
- if (ferror (stream)) {
- result++;
- goto all_done;
- }
- goto process_partial_block;
- }
-
- /* We've read at least one byte, so ignore errors. But always
- check for EOF, since feof may be true even though N > 0.
- Otherwise, we could end up calling fread after EOF. */
- if (feof (stream))
- goto process_partial_block;
- }
-
- /* Process buffer */
- sha1_hash(buffer, BLOCKSIZE, cx);
- }
-
-process_partial_block:
-
- /* Process any remaining bytes. */
- if (sum > 0)
- sha1_hash(buffer, sum, cx);
-
- /* Finalize and write the hash into our buffer. */
- sha1_end(hashval, cx);
-
-all_done:
-
- RELEASE_CONFIG_BUFFER(buffer);
- return result;
-}
-
-#define FLAG_SILENT 1
-#define FLAG_CHECK 2
-#define FLAG_WARN 4
-
-static unsigned char *hash_bin_to_hex(unsigned char *hash_value, unsigned char hash_length)
-{
- int x, len, max;
- unsigned char *hex_value;
-
- max = (hash_length * 2) + 2;
- hex_value = xmalloc(max);
- for (x = len = 0; x < hash_length; x++) {
- len += snprintf(hex_value+len, max-len, "%02x", hash_value[x]);
- }
- return(hex_value);
-}
-
-FILE *wfopen_file_or_stdin(const char *file_ptr)
-{
- FILE *stream;
-
- if ((file_ptr[0] == '-') && (file_ptr[1] == '\0')) {
- stream = stdin;
- } else {
- stream = bb_wfopen(file_ptr, "r");
- }
-
- return(stream);
-}
-
-/* This could become a common function for md5 as well, by using md5_stream */
-extern int authenticate(int argc, char **argv,
- int (*hash_ptr)(FILE *stream, unsigned char *hashval),
- const unsigned char hash_length)
-{
- unsigned char hash_value[hash_length];
- unsigned int flags;
- int return_value = EXIT_SUCCESS;
-
-#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
- flags = bb_getopt_ulflags(argc, argv, "scw");
-#else
- flags = bb_getopt_ulflags(argc, argv, "s");
-#endif
-
-#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
- if (!(flags & FLAG_CHECK)) {
- if (flags & FLAG_SILENT) {
- bb_error_msg_and_die("the -s option is meaningful only when verifying checksums");
- }
- else if (flags & FLAG_WARN) {
- bb_error_msg_and_die("the -w option is meaningful only when verifying checksums");
- }
- }
-#endif
-
- if (argc == optind) {
- argv[argc++] = "-";
- }
-
-#ifdef CONFIG_FEATURE_SHA1SUM_CHECK
- if (flags & FLAG_CHECK) {
- FILE *pre_computed_stream;
- int count_total = 0;
- int count_failed = 0;
- unsigned char *file_ptr = argv[optind];
-
- if (optind + 1 != argc) {
- bb_error_msg_and_die("only one argument may be specified when using -c");
- }
- pre_computed_stream = wfopen_file_or_stdin(file_ptr);
- while (!feof(pre_computed_stream) && !ferror(pre_computed_stream)) {
- FILE *stream;
- char *line;
- char *line_ptr;
- char *hex_value;
-
- line = bb_get_chomped_line_from_file(pre_computed_stream);
- if (line == NULL) {
- break;
- }
- count_total++;
- line_ptr = strchr(line, ' ');
- if (line_ptr == NULL) {
- if (flags & FLAG_WARN) {
- bb_error_msg("Invalid format");
- }
- free(line);
- continue;
- }
- *line_ptr = '\0';
- line_ptr++;
- if ((flags & FLAG_WARN) && (*line_ptr != ' ')) {
- bb_error_msg("Invalid format");
- free(line);
- continue;
- }
- line_ptr++;
- stream = bb_wfopen(line_ptr, "r");
- if (hash_ptr(stream, hash_value) == EXIT_FAILURE) {
- bb_perror_msg("%s", file_ptr);
- return_value = EXIT_FAILURE;
- }
- if (fclose(stream) == EOF) {
- bb_perror_msg("Couldnt close file %s", file_ptr);
- }
- hex_value = hash_bin_to_hex(hash_value, hash_length);
- printf("%s: ", line_ptr);
- if (strcmp(hex_value, line) != 0) {
- puts("FAILED");
- count_failed++;
- } else {
- puts("ok");
- }
- free(line);
- }
- if (count_failed) {
- bb_error_msg("WARNING: %d of %d computed checksum did NOT match", count_failed, count_total);
- }
- if (bb_fclose_nonstdin(pre_computed_stream) == EOF) {
- bb_perror_msg_and_die("Couldnt close file %s", file_ptr);
- }
- } else
-#endif
- while (optind < argc) {
- FILE *stream;
- unsigned char *file_ptr = argv[optind];
-
- optind++;
-
- stream = wfopen_file_or_stdin(file_ptr);
- if (stream == NULL) {
- return_value = EXIT_FAILURE;
- continue;
- }
- if (hash_ptr(stream, hash_value) == EXIT_FAILURE) {
- bb_perror_msg("%s", file_ptr);
- return_value = EXIT_FAILURE;
- }
- else if (!flags & FLAG_SILENT) {
- char *hex_value = hash_bin_to_hex(hash_value, hash_length);
- printf("%s %s\n", hex_value, file_ptr);
- free(hex_value);
- }
-
- if (bb_fclose_nonstdin(stream) == EOF) {
- bb_perror_msg("Couldnt close file %s", file_ptr);
- return_value = EXIT_FAILURE;
- }
- }
-
- return(return_value);
-}
-
-extern int sha1sum_main(int argc, char **argv)
-{
- return (authenticate(argc, argv, sha1sum_stream, SHA1_HASH_SIZE));
-}
diff --git a/release/src/router/busybox/coreutils/sleep.c b/release/src/router/busybox/coreutils/sleep.c
index 506192dd..de18dd0d 100644
--- a/release/src/router/busybox/coreutils/sleep.c
+++ b/release/src/router/busybox/coreutils/sleep.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
@@ -31,56 +18,87 @@
* time suffixes for seconds, minutes, hours, and days.
*/
-#include <stdlib.h>
-#include <limits.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-#ifdef CONFIG_FEATURE_FANCY_SLEEP
-static const struct suffix_mult sleep_suffixes[] = {
+/* This is a NOFORK applet. Be very careful! */
+
+
+#if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP
+static const struct suffix_mult sfx[] = {
{ "s", 1 },
{ "m", 60 },
{ "h", 60*60 },
{ "d", 24*60*60 },
- { NULL, 0 }
+ { }
};
#endif
-extern int sleep_main(int argc, char **argv)
+int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sleep_main(int argc UNUSED_PARAM, char **argv)
{
- unsigned int duration;
-
-#ifdef CONFIG_FEATURE_FANCY_SLEEP
+#if ENABLE_FEATURE_FLOAT_SLEEP
+ double duration;
+ struct timespec ts;
+#else
+ unsigned duration;
+#endif
- if (argc < 2) {
+ ++argv;
+ if (!*argv)
bb_show_usage();
- }
- ++argv;
+#if ENABLE_FEATURE_FLOAT_SLEEP
+
duration = 0;
do {
- duration += bb_xgetularg_bnd_sfx(*argv, 10,
- 0, UINT_MAX-duration,
- sleep_suffixes);
+ char *arg = *argv;
+ if (strchr(arg, '.')) {
+ double d;
+ int len = strspn(arg, "0123456789.");
+ char sv = arg[len];
+ arg[len] = '\0';
+ d = bb_strtod(arg, NULL);
+ if (errno)
+ bb_show_usage();
+ arg[len] = sv;
+ len--;
+ sv = arg[len];
+ arg[len] = '1';
+ duration += d * xatoul_sfx(&arg[len], sfx);
+ arg[len] = sv;
+ } else
+ duration += xatoul_sfx(arg, sfx);
} while (*++argv);
-#else /* CONFIG_FEATURE_FANCY_SLEEP */
-
- if (argc != 2) {
- bb_show_usage();
+ ts.tv_sec = MAXINT(typeof(ts.tv_sec));
+ ts.tv_nsec = 0;
+ if (duration >= 0 && duration < ts.tv_sec) {
+ ts.tv_sec = duration;
+ ts.tv_nsec = (duration - ts.tv_sec) * 1000000000;
}
+ do {
+ errno = 0;
+ nanosleep(&ts, &ts);
+ } while (errno == EINTR);
-#if UINT_MAX == ULONG_MAX
- duration = bb_xgetularg10(argv[1]);
-#else
- duration = bb_xgetularg10_bnd(argv[1], 0, UINT_MAX);
-#endif
+#elif ENABLE_FEATURE_FANCY_SLEEP
+
+ duration = 0;
+ do {
+ duration += xatou_range_sfx(*argv, 0, UINT_MAX - duration, sfx);
+ } while (*++argv);
+ sleep(duration);
-#endif /* CONFIG_FEATURE_FANCY_SLEEP */
+#else /* simple */
- if (sleep(duration)) {
- bb_perror_nomsg_and_die();
- }
+ duration = xatou(*argv);
+ sleep(duration);
+ // Off. If it's really needed, provide example why
+ //if (sleep(duration)) {
+ // bb_perror_nomsg_and_die();
+ //}
+
+#endif
return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/coreutils/sort.c b/release/src/router/busybox/coreutils/sort.c
index 8cc4d888..fad6d124 100644
--- a/release/src/router/busybox/coreutils/sort.c
+++ b/release/src/router/busybox/coreutils/sort.c
@@ -1,100 +1,406 @@
/* vi: set sw=4 ts=4: */
/*
- * Mini sort implementation for busybox
+ * SuS3 compliant sort implementation for busybox
*
- * Copyright (C) 2000 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
+ * Copyright (C) 2004 by Rob Landley <rob@landley.net>
*
- * 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.
+ * MAINTAINER: Rob Landley <rob@landley.net>
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
+ * See SuS3 sort standard at:
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html
*/
-/* BB_AUDIT SUSv3 _NOT_ compliant -- a number of options are not supported. */
-/* http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html */
+#include "libbb.h"
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * Now does proper error checking on i/o. Plus some space savings.
- */
+/* This is a NOEXEC applet. Be very careful! */
+
+
+/*
+ sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...]
+ sort -c [-bdfinru][-t char][-k keydef][file]
+*/
+
+/* These are sort types */
+static const char OPT_STR[] ALIGN1 = "ngMucszbrdfimS:T:o:k:t:";
+enum {
+ FLAG_n = 1, /* Numeric sort */
+ FLAG_g = 2, /* Sort using strtod() */
+ FLAG_M = 4, /* Sort date */
+/* ucsz apply to root level only, not keys. b at root level implies bb */
+ FLAG_u = 8, /* Unique */
+ FLAG_c = 0x10, /* Check: no output, exit(!ordered) */
+ FLAG_s = 0x20, /* Stable sort, no ascii fallback at end */
+ FLAG_z = 0x40, /* Input and output is NUL terminated, not \n */
+/* These can be applied to search keys, the previous four can't */
+ FLAG_b = 0x80, /* Ignore leading blanks */
+ FLAG_r = 0x100, /* Reverse */
+ FLAG_d = 0x200, /* Ignore !(isalnum()|isspace()) */
+ FLAG_f = 0x400, /* Force uppercase */
+ FLAG_i = 0x800, /* Ignore !isprint() */
+ FLAG_m = 0x1000, /* ignored: merge already sorted files; do not sort */
+ FLAG_S = 0x2000, /* ignored: -S, --buffer-size=SIZE */
+ FLAG_T = 0x4000, /* ignored: -T, --temporary-directory=DIR */
+ FLAG_o = 0x8000,
+ FLAG_k = 0x10000,
+ FLAG_t = 0x20000,
+ FLAG_bb = 0x80000000, /* Ignore trailing blanks */
+};
+
+#if ENABLE_FEATURE_SORT_BIG
+static char key_separator;
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
-#include "libcoreutils/coreutils.h"
+static struct sort_key {
+ struct sort_key *next_key; /* linked list */
+ unsigned range[4]; /* start word, start char, end word, end char */
+ unsigned flags;
+} *key_list;
-static int compare_ascii(const void *x, const void *y)
+static char *get_key(char *str, struct sort_key *key, int flags)
{
- return strcmp(*(char **)x, *(char **)y);
+ int start = 0, end = 0, len, j;
+ unsigned i;
+
+ /* Special case whole string, so we don't have to make a copy */
+ if (key->range[0] == 1 && !key->range[1] && !key->range[2] && !key->range[3]
+ && !(flags & (FLAG_b | FLAG_d | FLAG_f | FLAG_i | FLAG_bb))
+ ) {
+ return str;
+ }
+
+ /* Find start of key on first pass, end on second pass */
+ len = strlen(str);
+ for (j = 0; j < 2; j++) {
+ if (!key->range[2*j])
+ end = len;
+ /* Loop through fields */
+ else {
+ end = 0;
+ for (i = 1; i < key->range[2*j] + j; i++) {
+ if (key_separator) {
+ /* Skip body of key and separator */
+ while (str[end]) {
+ if (str[end++] == key_separator)
+ break;
+ }
+ } else {
+ /* Skip leading blanks */
+ while (isspace(str[end]))
+ end++;
+ /* Skip body of key */
+ while (str[end]) {
+ if (isspace(str[end]))
+ break;
+ end++;
+ }
+ }
+ }
+ }
+ if (!j) start = end;
+ }
+ /* Strip leading whitespace if necessary */
+//XXX: skip_whitespace()
+ if (flags & FLAG_b)
+ while (isspace(str[start])) start++;
+ /* Strip trailing whitespace if necessary */
+ if (flags & FLAG_bb)
+ while (end > start && isspace(str[end-1])) end--;
+ /* Handle offsets on start and end */
+ if (key->range[3]) {
+ end += key->range[3] - 1;
+ if (end > len) end = len;
+ }
+ if (key->range[1]) {
+ start += key->range[1] - 1;
+ if (start > len) start = len;
+ }
+ /* Make the copy */
+ if (end < start) end = start;
+ str = xstrndup(str+start, end-start);
+ /* Handle -d */
+ if (flags & FLAG_d) {
+ for (start = end = 0; str[end]; end++)
+ if (isspace(str[end]) || isalnum(str[end]))
+ str[start++] = str[end];
+ str[start] = '\0';
+ }
+ /* Handle -i */
+ if (flags & FLAG_i) {
+ for (start = end = 0; str[end]; end++)
+ if (isprint(str[end]))
+ str[start++] = str[end];
+ str[start] = '\0';
+ }
+ /* Handle -f */
+ if (flags & FLAG_f)
+ for (i = 0; str[i]; i++)
+ str[i] = toupper(str[i]);
+
+ return str;
}
-static int compare_numeric(const void *x, const void *y)
+static struct sort_key *add_key(void)
{
- int z = atoi(*(char **)x) - atoi(*(char **)y);
- return z ? z : strcmp(*(char **)x, *(char **)y);
+ struct sort_key **pkey = &key_list;
+ while (*pkey)
+ pkey = &((*pkey)->next_key);
+ return *pkey = xzalloc(sizeof(struct sort_key));
}
-int sort_main(int argc, char **argv)
+#define GET_LINE(fp) \
+ ((option_mask32 & FLAG_z) \
+ ? bb_get_chunk_from_file(fp, NULL) \
+ : xmalloc_fgetline(fp))
+#else
+#define GET_LINE(fp) xmalloc_fgetline(fp)
+#endif
+
+/* Iterate through keys list and perform comparisons */
+static int compare_keys(const void *xarg, const void *yarg)
{
- FILE *fp;
- char *line, **lines = NULL;
- int i, nlines = 0, inc;
- int (*compare)(const void *, const void *) = compare_ascii;
+ int flags = option_mask32, retval = 0;
+ char *x, *y;
- int flags;
+#if ENABLE_FEATURE_SORT_BIG
+ struct sort_key *key;
- bb_default_error_retval = 2;
+ for (key = key_list; !retval && key; key = key->next_key) {
+ flags = key->flags ? key->flags : option_mask32;
+ /* Chop out and modify key chunks, handling -dfib */
+ x = get_key(*(char **)xarg, key, flags);
+ y = get_key(*(char **)yarg, key, flags);
+#else
+ /* This curly bracket serves no purpose but to match the nesting
+ level of the for () loop we're not using */
+ {
+ x = *(char **)xarg;
+ y = *(char **)yarg;
+#endif
+ /* Perform actual comparison */
+ switch (flags & 7) {
+ default:
+ bb_error_msg_and_die("unknown sort type");
+ break;
+ /* Ascii sort */
+ case 0:
+#if ENABLE_LOCALE_SUPPORT
+ retval = strcoll(x, y);
+#else
+ retval = strcmp(x, y);
+#endif
+ break;
+#if ENABLE_FEATURE_SORT_BIG
+ case FLAG_g: {
+ char *xx, *yy;
+ double dx = strtod(x, &xx);
+ double dy = strtod(y, &yy);
+ /* not numbers < NaN < -infinity < numbers < +infinity) */
+ if (x == xx)
+ retval = (y == yy ? 0 : -1);
+ else if (y == yy)
+ retval = 1;
+ /* Check for isnan */
+ else if (dx != dx)
+ retval = (dy != dy) ? 0 : -1;
+ else if (dy != dy)
+ retval = 1;
+ /* Check for infinity. Could underflow, but it avoids libm. */
+ else if (1.0 / dx == 0.0) {
+ if (dx < 0)
+ retval = (1.0 / dy == 0.0 && dy < 0) ? 0 : -1;
+ else
+ retval = (1.0 / dy == 0.0 && dy > 0) ? 0 : 1;
+ } else if (1.0 / dy == 0.0)
+ retval = (dy < 0) ? 1 : -1;
+ else
+ retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
+ break;
+ }
+ case FLAG_M: {
+ struct tm thyme;
+ int dx;
+ char *xx, *yy;
+
+ xx = strptime(x, "%b", &thyme);
+ dx = thyme.tm_mon;
+ yy = strptime(y, "%b", &thyme);
+ if (!xx)
+ retval = (!yy) ? 0 : -1;
+ else if (!yy)
+ retval = 1;
+ else
+ retval = (dx == thyme.tm_mon) ? 0 : dx - thyme.tm_mon;
+ break;
+ }
+ /* Full floating point version of -n */
+ case FLAG_n: {
+ double dx = atof(x);
+ double dy = atof(y);
+ retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0);
+ break;
+ }
+ } /* switch */
+ /* Free key copies. */
+ if (x != *(char **)xarg) free(x);
+ if (y != *(char **)yarg) free(y);
+ /* if (retval) break; - done by for () anyway */
+#else
+ /* Integer version of -n for tiny systems */
+ case FLAG_n:
+ retval = atoi(x) - atoi(y);
+ break;
+ } /* switch */
+#endif
+ } /* for */
+
+ /* Perform fallback sort if necessary */
+ if (!retval && !(option_mask32 & FLAG_s))
+ retval = strcmp(*(char **)xarg, *(char **)yarg);
+
+ if (flags & FLAG_r) return -retval;
+ return retval;
+}
+
+#if ENABLE_FEATURE_SORT_BIG
+static unsigned str2u(char **str)
+{
+ unsigned long lu;
+ if (!isdigit((*str)[0]))
+ bb_error_msg_and_die("bad field specification");
+ lu = strtoul(*str, str, 10);
+ if ((sizeof(long) > sizeof(int) && lu > INT_MAX) || !lu)
+ bb_error_msg_and_die("bad field specification");
+ return lu;
+}
+#endif
- flags = bb_getopt_ulflags(argc, argv, "nru");
- if (flags & 1) {
- compare = compare_numeric;
+int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sort_main(int argc UNUSED_PARAM, char **argv)
+{
+ FILE *fp, *outfile = stdout;
+ char *line, **lines = NULL;
+ char *str_ignored, *str_o, *str_t;
+ llist_t *lst_k = NULL;
+ int i, flag;
+ int linecount = 0;
+
+ xfunc_error_retval = 2;
+
+ /* Parse command line options */
+ /* -o and -t can be given at most once */
+ opt_complementary = "o--o:t--t:" /* -t, -o: maximum one of each */
+ "k::"; /* -k takes list */
+ getopt32(argv, OPT_STR, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t);
+#if ENABLE_FEATURE_SORT_BIG
+ if (option_mask32 & FLAG_o) outfile = xfopen_for_write(str_o);
+ if (option_mask32 & FLAG_t) {
+ if (!str_t[0] || str_t[1])
+ bb_error_msg_and_die("bad -t parameter");
+ key_separator = str_t[0];
}
+ /* parse sort key */
+ while (lst_k) {
+ enum {
+ FLAG_allowed_for_k =
+ FLAG_n | /* Numeric sort */
+ FLAG_g | /* Sort using strtod() */
+ FLAG_M | /* Sort date */
+ FLAG_b | /* Ignore leading blanks */
+ FLAG_r | /* Reverse */
+ FLAG_d | /* Ignore !(isalnum()|isspace()) */
+ FLAG_f | /* Force uppercase */
+ FLAG_i | /* Ignore !isprint() */
+ 0
+ };
+ struct sort_key *key = add_key();
+ char *str_k = llist_pop(&lst_k);
+ const char *temp2;
- argv += optind;
- if (!*argv) {
- *--argv = "-";
+ i = 0; /* i==0 before comma, 1 after (-k3,6) */
+ while (*str_k) {
+ /* Start of range */
+ /* Cannot use bb_strtou - suffix can be a letter */
+ key->range[2*i] = str2u(&str_k);
+ if (*str_k == '.') {
+ str_k++;
+ key->range[2*i+1] = str2u(&str_k);
+ }
+ while (*str_k) {
+ if (*str_k == ',' && !i++) {
+ str_k++;
+ break;
+ } /* no else needed: fall through to syntax error
+ because comma isn't in OPT_STR */
+ temp2 = strchr(OPT_STR, *str_k);
+ if (!temp2)
+ bb_error_msg_and_die("unknown key option");
+ flag = 1 << (temp2 - OPT_STR);
+ if (flag & ~FLAG_allowed_for_k)
+ bb_error_msg_and_die("unknown sort type");
+ /* b after ',' means strip _trailing_ space */
+ if (i && flag == FLAG_b) flag = FLAG_bb;
+ key->flags |= flag;
+ str_k++;
+ }
+ }
}
+#endif
+ /* global b strips leading and trailing spaces */
+ if (option_mask32 & FLAG_b) option_mask32 |= FLAG_bb;
+ /* Open input files and read data */
+ argv += optind;
+ if (!*argv)
+ *--argv = (char*)"-";
do {
- fp = xgetoptfile_sort_uniq(argv, "r");
- while ((line = bb_get_chomped_line_from_file(fp)) != NULL) {
- lines = xrealloc(lines, sizeof(char *) * (nlines + 1));
- lines[nlines++] = line;
+ /* coreutils 6.9 compat: abort on first open error,
+ * do not continue to next file: */
+ fp = xfopen_stdin(*argv);
+ for (;;) {
+ line = GET_LINE(fp);
+ if (!line) break;
+ lines = xrealloc_vector(lines, 6, linecount);
+ lines[linecount++] = line;
}
- bb_xferror(fp, *argv);
- bb_fclose_nonstdin(fp);
+ fclose_if_not_stdin(fp);
} while (*++argv);
- /* sort it */
- qsort(lines, nlines, sizeof(char *), compare);
-
- /* print it */
- i = 0;
- --nlines;
- if ((inc = 1 - (flags & 2)) < 0) { /* reverse */
- i = nlines;
+#if ENABLE_FEATURE_SORT_BIG
+ /* if no key, perform alphabetic sort */
+ if (!key_list)
+ add_key()->range[0] = 1;
+ /* handle -c */
+ if (option_mask32 & FLAG_c) {
+ int j = (option_mask32 & FLAG_u) ? -1 : 0;
+ for (i = 1; i < linecount; i++)
+ if (compare_keys(&lines[i-1], &lines[i]) > j) {
+ fprintf(stderr, "Check line %d\n", i);
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
- flags &= 4;
-
- while (nlines >= 0) {
- if (!flags || !nlines || strcmp(lines[i+inc], lines[i])) {
- puts(lines[i]);
+#endif
+ /* Perform the actual sort */
+ qsort(lines, linecount, sizeof(char *), compare_keys);
+ /* handle -u */
+ if (option_mask32 & FLAG_u) {
+ flag = 0;
+ /* coreutils 6.3 drop lines for which only key is the same */
+ /* -- disabling last-resort compare... */
+ option_mask32 |= FLAG_s;
+ for (i = 1; i < linecount; i++) {
+ if (!compare_keys(&lines[flag], &lines[i]))
+ free(lines[i]);
+ else
+ lines[++flag] = lines[i];
}
- i += inc;
- --nlines;
+ if (linecount) linecount = flag+1;
}
+ /* Print it */
+ flag = (option_mask32 & FLAG_z) ? '\0' : '\n';
+ for (i = 0; i < linecount; i++)
+ fprintf(outfile, "%s%c", lines[i], flag);
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
}
diff --git a/release/src/router/busybox/coreutils/split.c b/release/src/router/busybox/coreutils/split.c
new file mode 100644
index 00000000..f1ec64be
--- /dev/null
+++ b/release/src/router/busybox/coreutils/split.c
@@ -0,0 +1,139 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * split - split a file into pieces
+ * Copyright (c) 2007 Bernhard Reutner-Fischer
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+/* BB_AUDIT: SUSv3 compliant
+ * SUSv3 requirements:
+ * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html
+ */
+#include "libbb.h"
+
+static const struct suffix_mult split_suffices[] = {
+#if ENABLE_FEATURE_SPLIT_FANCY
+ { "b", 512 },
+#endif
+ { "k", 1024 },
+ { "m", 1024*1024 },
+#if ENABLE_FEATURE_SPLIT_FANCY
+ { "g", 1024*1024*1024 },
+#endif
+ { }
+};
+
+/* Increment the suffix part of the filename.
+ * Returns NULL if we are out of filenames.
+ */
+static char *next_file(char *old, unsigned suffix_len)
+{
+ size_t end = strlen(old);
+ unsigned i = 1;
+ char *curr;
+
+ do {
+ curr = old + end - i;
+ if (*curr < 'z') {
+ *curr += 1;
+ break;
+ }
+ i++;
+ if (i > suffix_len) {
+ return NULL;
+ }
+ *curr = 'a';
+ } while (1);
+
+ return old;
+}
+
+#define read_buffer bb_common_bufsiz1
+enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 };
+
+#define SPLIT_OPT_l (1<<0)
+#define SPLIT_OPT_b (1<<1)
+#define SPLIT_OPT_a (1<<2)
+
+int split_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int split_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned suffix_len = 2;
+ char *pfx;
+ char *count_p;
+ const char *sfx;
+ off_t cnt = 1000;
+ off_t remaining = 0;
+ unsigned opt;
+ ssize_t bytes_read, to_write;
+ char *src;
+
+ opt_complementary = "?2:a+"; /* max 2 args; -a N */
+ opt = getopt32(argv, "l:b:a:", &count_p, &count_p, &suffix_len);
+
+ if (opt & SPLIT_OPT_l)
+ cnt = XATOOFF(count_p);
+ if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF
+ cnt = xatoull_sfx(count_p, split_suffices);
+ sfx = "x";
+
+ argv += optind;
+ if (argv[0]) {
+ if (argv[1])
+ sfx = argv[1];
+ xmove_fd(xopen(argv[0], O_RDONLY), 0);
+ } else {
+ argv[0] = (char *) bb_msg_standard_input;
+ }
+
+ if (NAME_MAX < strlen(sfx) + suffix_len)
+ bb_error_msg_and_die("suffix too long");
+
+ {
+ char *char_p = xzalloc(suffix_len + 1);
+ memset(char_p, 'a', suffix_len);
+ pfx = xasprintf("%s%s", sfx, char_p);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(char_p);
+ }
+
+ while (1) {
+ bytes_read = safe_read(STDIN_FILENO, read_buffer, READ_BUFFER_SIZE);
+ if (!bytes_read)
+ break;
+ if (bytes_read < 0)
+ bb_simple_perror_msg_and_die(argv[0]);
+ src = read_buffer;
+ do {
+ if (!remaining) {
+ if (!pfx)
+ bb_error_msg_and_die("suffixes exhausted");
+ xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1);
+ pfx = next_file(pfx, suffix_len);
+ remaining = cnt;
+ }
+
+ if (opt & SPLIT_OPT_b) {
+ /* split by bytes */
+ to_write = (bytes_read < remaining) ? bytes_read : remaining;
+ remaining -= to_write;
+ } else {
+ /* split by lines */
+ /* can be sped up by using _memrchr_
+ * and writing many lines at once... */
+ char *end = memchr(src, '\n', bytes_read);
+ if (end) {
+ --remaining;
+ to_write = end - src + 1;
+ } else {
+ to_write = bytes_read;
+ }
+ }
+
+ xwrite(STDOUT_FILENO, src, to_write);
+ bytes_read -= to_write;
+ src += to_write;
+ } while (bytes_read);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/coreutils/stat.c b/release/src/router/busybox/coreutils/stat.c
new file mode 100644
index 00000000..32e8b42f
--- /dev/null
+++ b/release/src/router/busybox/coreutils/stat.c
@@ -0,0 +1,669 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * stat -- display file or file system status
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation.
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ * Copyright (C) 2006 by Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Written by Michael Meskes
+ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+#include "libbb.h"
+
+/* vars to control behavior */
+#define OPT_FILESYS (1 << 0)
+#define OPT_TERSE (1 << 1)
+#define OPT_DEREFERENCE (1 << 2)
+#define OPT_SELINUX (1 << 3)
+
+#if ENABLE_FEATURE_STAT_FORMAT
+typedef bool (*statfunc_ptr)(const char *, const char *);
+#else
+typedef bool (*statfunc_ptr)(const char *);
+#endif
+
+static const char *file_type(const struct stat *st)
+{
+ /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107
+ * for some of these formats.
+ * To keep diagnostics grammatical in English, the
+ * returned string must start with a consonant.
+ */
+ if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file";
+ if (S_ISDIR(st->st_mode)) return "directory";
+ if (S_ISBLK(st->st_mode)) return "block special file";
+ if (S_ISCHR(st->st_mode)) return "character special file";
+ if (S_ISFIFO(st->st_mode)) return "fifo";
+ if (S_ISLNK(st->st_mode)) return "symbolic link";
+ if (S_ISSOCK(st->st_mode)) return "socket";
+ if (S_TYPEISMQ(st)) return "message queue";
+ if (S_TYPEISSEM(st)) return "semaphore";
+ if (S_TYPEISSHM(st)) return "shared memory object";
+#ifdef S_TYPEISTMO
+ if (S_TYPEISTMO(st)) return "typed memory object";
+#endif
+ return "weird file";
+}
+
+static const char *human_time(time_t t)
+{
+ /* Old
+ static char *str;
+ str = ctime(&t);
+ str[strlen(str)-1] = '\0';
+ return str;
+ */
+ /* coreutils 6.3 compat: */
+
+ /*static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")] ALIGN1;*/
+#define buf bb_common_bufsiz1
+
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t));
+ return buf;
+#undef buf
+}
+
+/* Return the type of the specified file system.
+ * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
+ * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
+ * Still others have neither and have to get by with f_type (Linux).
+ */
+static const char *human_fstype(uint32_t f_type)
+{
+ static const struct types {
+ uint32_t type;
+ const char *const fs;
+ } humantypes[] = {
+ { 0xADFF, "affs" },
+ { 0x1Cd1, "devpts" },
+ { 0x137D, "ext" },
+ { 0xEF51, "ext2" },
+ { 0xEF53, "ext2/ext3" },
+ { 0x3153464a, "jfs" },
+ { 0x58465342, "xfs" },
+ { 0xF995E849, "hpfs" },
+ { 0x9660, "isofs" },
+ { 0x4000, "isofs" },
+ { 0x4004, "isofs" },
+ { 0x137F, "minix" },
+ { 0x138F, "minix (30 char.)" },
+ { 0x2468, "minix v2" },
+ { 0x2478, "minix v2 (30 char.)" },
+ { 0x4d44, "msdos" },
+ { 0x4006, "fat" },
+ { 0x564c, "novell" },
+ { 0x6969, "nfs" },
+ { 0x9fa0, "proc" },
+ { 0x517B, "smb" },
+ { 0x012FF7B4, "xenix" },
+ { 0x012FF7B5, "sysv4" },
+ { 0x012FF7B6, "sysv2" },
+ { 0x012FF7B7, "coh" },
+ { 0x00011954, "ufs" },
+ { 0x012FD16D, "xia" },
+ { 0x5346544e, "ntfs" },
+ { 0x1021994, "tmpfs" },
+ { 0x52654973, "reiserfs" },
+ { 0x28cd3d45, "cramfs" },
+ { 0x7275, "romfs" },
+ { 0x858458f6, "romfs" },
+ { 0x73717368, "squashfs" },
+ { 0x62656572, "sysfs" },
+ { 0, "UNKNOWN" }
+ };
+
+ int i;
+
+ for (i = 0; humantypes[i].type; ++i)
+ if (humantypes[i].type == f_type)
+ break;
+ return humantypes[i].fs;
+}
+
+/* "man statfs" says that statfsbuf->f_fsid is a mess */
+/* coreutils treats it as an array of ints, most significant first */
+static unsigned long long get_f_fsid(const struct statfs *statfsbuf)
+{
+ const unsigned *p = (const void*) &statfsbuf->f_fsid;
+ unsigned sz = sizeof(statfsbuf->f_fsid) / sizeof(unsigned);
+ unsigned long long r = 0;
+
+ do
+ r = (r << (sizeof(unsigned)*8)) | *p++;
+ while (--sz > 0);
+ return r;
+}
+
+#if ENABLE_FEATURE_STAT_FORMAT
+static void strcatc(char *str, char c)
+{
+ int len = strlen(str);
+ str[len++] = c;
+ str[len] = '\0';
+}
+
+static void printfs(char *pformat, const char *msg)
+{
+ strcatc(pformat, 's');
+ printf(pformat, msg);
+}
+
+/* print statfs info */
+static void print_statfs(char *pformat, const char m,
+ const char *const filename, const void *data
+ USE_SELINUX(, security_context_t scontext))
+{
+ const struct statfs *statfsbuf = data;
+ if (m == 'n') {
+ printfs(pformat, filename);
+ } else if (m == 'i') {
+ strcat(pformat, "llx");
+ printf(pformat, get_f_fsid(statfsbuf));
+ } else if (m == 'l') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) (statfsbuf->f_namelen));
+ } else if (m == 't') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) (statfsbuf->f_type)); /* no equiv */
+ } else if (m == 'T') {
+ printfs(pformat, human_fstype(statfsbuf->f_type));
+ } else if (m == 'b') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_blocks));
+ } else if (m == 'f') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_bfree));
+ } else if (m == 'a') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_bavail));
+ } else if (m == 's' || m == 'S') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) (statfsbuf->f_bsize));
+ } else if (m == 'c') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_files));
+ } else if (m == 'd') {
+ strcat(pformat, "jd");
+ printf(pformat, (intmax_t) (statfsbuf->f_ffree));
+#if ENABLE_SELINUX
+ } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
+ printfs(pformat, scontext);
+#endif
+ } else {
+ strcatc(pformat, 'c');
+ printf(pformat, m);
+ }
+}
+
+/* print stat info */
+static void print_stat(char *pformat, const char m,
+ const char *const filename, const void *data
+ USE_SELINUX(, security_context_t scontext))
+{
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+ struct stat *statbuf = (struct stat *) data;
+ struct passwd *pw_ent;
+ struct group *gw_ent;
+
+ if (m == 'n') {
+ printfs(pformat, filename);
+ } else if (m == 'N') {
+ strcatc(pformat, 's');
+ if (S_ISLNK(statbuf->st_mode)) {
+ char *linkname = xmalloc_readlink_or_warn(filename);
+ if (linkname == NULL)
+ return;
+ /*printf("\"%s\" -> \"%s\"", filename, linkname); */
+ printf(pformat, filename);
+ printf(" -> ");
+ printf(pformat, linkname);
+ free(linkname);
+ } else {
+ printf(pformat, filename);
+ }
+ } else if (m == 'd') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_dev);
+ } else if (m == 'D') {
+ strcat(pformat, "jx");
+ printf(pformat, (uintmax_t) statbuf->st_dev);
+ } else if (m == 'i') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_ino);
+ } else if (m == 'a') {
+ strcat(pformat, "lo");
+ printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)));
+ } else if (m == 'A') {
+ printfs(pformat, bb_mode_string(statbuf->st_mode));
+ } else if (m == 'f') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) statbuf->st_mode);
+ } else if (m == 'F') {
+ printfs(pformat, file_type(statbuf));
+ } else if (m == 'h') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_nlink);
+ } else if (m == 'u') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_uid);
+ } else if (m == 'U') {
+ setpwent();
+ pw_ent = getpwuid(statbuf->st_uid);
+ printfs(pformat, (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN");
+ } else if (m == 'g') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_gid);
+ } else if (m == 'G') {
+ setgrent();
+ gw_ent = getgrgid(statbuf->st_gid);
+ printfs(pformat, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
+ } else if (m == 't') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) major(statbuf->st_rdev));
+ } else if (m == 'T') {
+ strcat(pformat, "lx");
+ printf(pformat, (unsigned long) minor(statbuf->st_rdev));
+ } else if (m == 's') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) (statbuf->st_size));
+ } else if (m == 'B') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) 512); //ST_NBLOCKSIZE
+ } else if (m == 'b') {
+ strcat(pformat, "ju");
+ printf(pformat, (uintmax_t) statbuf->st_blocks);
+ } else if (m == 'o') {
+ strcat(pformat, "lu");
+ printf(pformat, (unsigned long) statbuf->st_blksize);
+ } else if (m == 'x') {
+ printfs(pformat, human_time(statbuf->st_atime));
+ } else if (m == 'X') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_atime);
+ } else if (m == 'y') {
+ printfs(pformat, human_time(statbuf->st_mtime));
+ } else if (m == 'Y') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_mtime);
+ } else if (m == 'z') {
+ printfs(pformat, human_time(statbuf->st_ctime));
+ } else if (m == 'Z') {
+ strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu");
+ printf(pformat, (unsigned long) statbuf->st_ctime);
+#if ENABLE_SELINUX
+ } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) {
+ printfs(pformat, scontext);
+#endif
+ } else {
+ strcatc(pformat, 'c');
+ printf(pformat, m);
+ }
+}
+
+static void print_it(const char *masterformat, const char *filename,
+ void (*print_func) (char*, char, const char*, const void* USE_SELINUX(, security_context_t scontext)),
+ const void *data
+ USE_SELINUX(, security_context_t scontext) )
+{
+ /* Create a working copy of the format string */
+ char *format = xstrdup(masterformat);
+ /* Add 2 to accomodate our conversion of the stat '%s' format string
+ * to the printf '%llu' one. */
+ char *dest = xmalloc(strlen(format) + 2 + 1);
+ char *b;
+
+ b = format;
+ while (b) {
+ size_t len;
+ char *p = strchr(b, '%');
+ if (!p) {
+ /* coreutils 6.3 always prints <cr> at the end */
+ /*fputs(b, stdout);*/
+ puts(b);
+ break;
+ }
+ *p++ = '\0';
+ fputs(b, stdout);
+
+ /* dest = "%<modifiers>" */
+ len = strspn(p, "#-+.I 0123456789");
+ dest[0] = '%';
+ memcpy(dest + 1, p, len);
+ dest[1 + len] = '\0';
+ p += len;
+
+ b = p + 1;
+ switch (*p) {
+ case '\0':
+ b = NULL;
+ /* fall through */
+ case '%':
+ bb_putchar('%');
+ break;
+ default:
+ /* Completes "%<modifiers>" with specifier and printfs */
+ print_func(dest, *p, filename, data USE_SELINUX(,scontext));
+ break;
+ }
+ }
+
+ free(format);
+ free(dest);
+}
+#endif
+
+/* Stat the file system and print what we find. */
+#if !ENABLE_FEATURE_STAT_FORMAT
+#define do_statfs(filename, format) do_statfs(filename)
+#endif
+static bool do_statfs(const char *filename, const char *format)
+{
+ struct statfs statfsbuf;
+
+#if !ENABLE_FEATURE_STAT_FORMAT
+ const char *format;
+#endif
+#if ENABLE_SELINUX
+ security_context_t scontext = NULL;
+
+ if (option_mask32 & OPT_SELINUX) {
+ if ((option_mask32 & OPT_DEREFERENCE
+ ? lgetfilecon(filename, &scontext)
+ : getfilecon(filename, &scontext)
+ ) < 0
+ ) {
+ bb_perror_msg(filename);
+ return 0;
+ }
+ }
+#endif
+ if (statfs(filename, &statfsbuf) != 0) {
+ bb_perror_msg("cannot read file system information for '%s'", filename);
+ return 0;
+ }
+
+#if ENABLE_FEATURE_STAT_FORMAT
+ if (format == NULL) {
+#if !ENABLE_SELINUX
+ format = (option_mask32 & OPT_TERSE
+ ? "%n %i %l %t %s %b %f %a %c %d\n"
+ : " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d");
+#else
+ format = (option_mask32 & OPT_TERSE
+ ? (option_mask32 & OPT_SELINUX ? "%n %i %l %t %s %b %f %a %c %d %C\n":
+ "%n %i %l %t %s %b %f %a %c %d\n")
+ : (option_mask32 & OPT_SELINUX ?
+ " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d"
+ " S_context: %C\n":
+ " File: \"%n\"\n"
+ " ID: %-8i Namelen: %-7l Type: %T\n"
+ "Block size: %-10s\n"
+ "Blocks: Total: %-10b Free: %-10f Available: %a\n"
+ "Inodes: Total: %-10c Free: %d\n")
+ );
+#endif /* SELINUX */
+ }
+ print_it(format, filename, print_statfs, &statfsbuf USE_SELINUX(, scontext));
+#else /* FEATURE_STAT_FORMAT */
+ format = (option_mask32 & OPT_TERSE
+ ? "%s %llx %lu "
+ : " File: \"%s\"\n"
+ " ID: %-8llx Namelen: %-7lu ");
+ printf(format,
+ filename,
+ get_f_fsid(&statfsbuf),
+ statfsbuf.f_namelen);
+
+ if (option_mask32 & OPT_TERSE)
+ printf("%lx ", (unsigned long) (statfsbuf.f_type));
+ else
+ printf("Type: %s\n", human_fstype(statfsbuf.f_type));
+
+#if !ENABLE_SELINUX
+ format = (option_mask32 & OPT_TERSE
+ ? "%lu %ld %ld %ld %ld %ld\n"
+ : "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd\n");
+ printf(format,
+ (unsigned long) (statfsbuf.f_bsize),
+ (intmax_t) (statfsbuf.f_blocks),
+ (intmax_t) (statfsbuf.f_bfree),
+ (intmax_t) (statfsbuf.f_bavail),
+ (intmax_t) (statfsbuf.f_files),
+ (intmax_t) (statfsbuf.f_ffree));
+#else
+ format = (option_mask32 & OPT_TERSE
+ ? (option_mask32 & OPT_SELINUX ? "%lu %ld %ld %ld %ld %ld %C\n":
+ "%lu %ld %ld %ld %ld %ld\n")
+ : (option_mask32 & OPT_SELINUX ?
+ "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd"
+ "S_context: %C\n":
+ "Block size: %-10lu\n"
+ "Blocks: Total: %-10jd Free: %-10jd Available: %jd\n"
+ "Inodes: Total: %-10jd Free: %jd\n"));
+ printf(format,
+ (unsigned long) (statfsbuf.f_bsize),
+ (intmax_t) (statfsbuf.f_blocks),
+ (intmax_t) (statfsbuf.f_bfree),
+ (intmax_t) (statfsbuf.f_bavail),
+ (intmax_t) (statfsbuf.f_files),
+ (intmax_t) (statfsbuf.f_ffree),
+ scontext);
+
+ if (scontext)
+ freecon(scontext);
+#endif
+#endif /* FEATURE_STAT_FORMAT */
+ return 1;
+}
+
+/* stat the file and print what we find */
+#if !ENABLE_FEATURE_STAT_FORMAT
+#define do_stat(filename, format) do_stat(filename)
+#endif
+static bool do_stat(const char *filename, const char *format)
+{
+ struct stat statbuf;
+#if ENABLE_SELINUX
+ security_context_t scontext = NULL;
+
+ if (option_mask32 & OPT_SELINUX) {
+ if ((option_mask32 & OPT_DEREFERENCE
+ ? lgetfilecon(filename, &scontext)
+ : getfilecon(filename, &scontext)
+ ) < 0
+ ) {
+ bb_perror_msg(filename);
+ return 0;
+ }
+ }
+#endif
+ if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) {
+ bb_perror_msg("cannot stat '%s'", filename);
+ return 0;
+ }
+
+#if ENABLE_FEATURE_STAT_FORMAT
+ if (format == NULL) {
+#if !ENABLE_SELINUX
+ if (option_mask32 & OPT_TERSE) {
+ format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
+ } else {
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
+ format =
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n";
+ } else {
+ format =
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n";
+ }
+ }
+#else
+ if (option_mask32 & OPT_TERSE) {
+ format = (option_mask32 & OPT_SELINUX ?
+ "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n":
+ "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n");
+ } else {
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) {
+ format = (option_mask32 & OPT_SELINUX ?
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ " S_Context: %C\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n":
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
+ " Device type: %t,%T\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n");
+ } else {
+ format = (option_mask32 & OPT_SELINUX ?
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "S_Context: %C\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n":
+ " File: \"%N\"\n"
+ " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
+ "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
+ "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
+ "Access: %x\n" "Modify: %y\n" "Change: %z\n");
+ }
+ }
+#endif
+ }
+ print_it(format, filename, print_stat, &statbuf USE_SELINUX(, scontext));
+#else /* FEATURE_STAT_FORMAT */
+ if (option_mask32 & OPT_TERSE) {
+ printf("%s %ju %ju %lx %lu %lu %jx %ju %lu %lx %lx %lu %lu %lu %lu"
+ SKIP_SELINUX("\n"),
+ filename,
+ (uintmax_t) (statbuf.st_size),
+ (uintmax_t) statbuf.st_blocks,
+ (unsigned long) statbuf.st_mode,
+ (unsigned long) statbuf.st_uid,
+ (unsigned long) statbuf.st_gid,
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_ino,
+ (unsigned long) statbuf.st_nlink,
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev),
+ (unsigned long) statbuf.st_atime,
+ (unsigned long) statbuf.st_mtime,
+ (unsigned long) statbuf.st_ctime,
+ (unsigned long) statbuf.st_blksize
+ );
+#if ENABLE_SELINUX
+ if (option_mask32 & OPT_SELINUX)
+ printf(" %lc\n", *scontext);
+ else
+ bb_putchar('\n');
+#endif
+ } else {
+ char *linkname = NULL;
+
+ struct passwd *pw_ent;
+ struct group *gw_ent;
+ setgrent();
+ gw_ent = getgrgid(statbuf.st_gid);
+ setpwent();
+ pw_ent = getpwuid(statbuf.st_uid);
+
+ if (S_ISLNK(statbuf.st_mode))
+ linkname = xmalloc_readlink_or_warn(filename);
+ if (linkname)
+ printf(" File: \"%s\" -> \"%s\"\n", filename, linkname);
+ else
+ printf(" File: \"%s\"\n", filename);
+
+ printf(" Size: %-10ju\tBlocks: %-10ju IO Block: %-6lu %s\n"
+ "Device: %jxh/%jud\tInode: %-10ju Links: %-5lu",
+ (uintmax_t) (statbuf.st_size),
+ (uintmax_t) statbuf.st_blocks,
+ (unsigned long) statbuf.st_blksize,
+ file_type(&statbuf),
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_dev,
+ (uintmax_t) statbuf.st_ino,
+ (unsigned long) statbuf.st_nlink);
+ if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode))
+ printf(" Device type: %lx,%lx\n",
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ else
+ bb_putchar('\n');
+ printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n",
+ (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)),
+ bb_mode_string(statbuf.st_mode),
+ (unsigned long) statbuf.st_uid,
+ (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN",
+ (unsigned long) statbuf.st_gid,
+ (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN");
+#if ENABLE_SELINUX
+ printf(" S_Context: %lc\n", *scontext);
+#endif
+ printf("Access: %s\n" "Modify: %s\n" "Change: %s\n",
+ human_time(statbuf.st_atime),
+ human_time(statbuf.st_mtime),
+ human_time(statbuf.st_ctime));
+ }
+#endif /* FEATURE_STAT_FORMAT */
+ return 1;
+}
+
+int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int stat_main(int argc, char **argv)
+{
+ USE_FEATURE_STAT_FORMAT(char *format = NULL;)
+ int i;
+ int ok = 1;
+ statfunc_ptr statfunc = do_stat;
+
+ getopt32(argv, "ftL"
+ USE_SELINUX("Z")
+ USE_FEATURE_STAT_FORMAT("c:", &format)
+ );
+
+ if (option_mask32 & OPT_FILESYS) /* -f */
+ statfunc = do_statfs;
+ if (argc == optind) /* files */
+ bb_show_usage();
+
+#if ENABLE_SELINUX
+ if (option_mask32 & OPT_SELINUX) {
+ selinux_or_die();
+ }
+#endif /* ENABLE_SELINUX */
+ for (i = optind; i < argc; ++i)
+ ok &= statfunc(argv[i] USE_FEATURE_STAT_FORMAT(, format));
+
+ return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/release/src/router/busybox/coreutils/stty.c b/release/src/router/busybox/coreutils/stty.c
index bd3a3691..3605e3c2 100644
--- a/release/src/router/busybox/coreutils/stty.c
+++ b/release/src/router/busybox/coreutils/stty.c
@@ -2,15 +2,8 @@
/* stty -- change and print terminal line settings
Copyright (C) 1990-1999 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
/* Usage: stty [-ag] [-F device] [setting...]
Options:
@@ -28,44 +21,16 @@
*/
-//#define TEST
-
-#include <stddef.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-
-#include <sys/param.h>
-#include <unistd.h>
-
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <memory.h>
-#include <fcntl.h>
-#include "busybox.h"
-
-#define STREQ(a, b) (strcmp ((a), (b)) == 0)
-
+#include "libbb.h"
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE ((unsigned char) 0)
#endif
#define Control(c) ((c) & 0x1f)
-/* Canonical values for control characters. */
+/* Canonical values for control characters */
#ifndef CINTR
-# define CINTR Control ('c')
+# define CINTR Control('c')
#endif
#ifndef CQUIT
# define CQUIT 28
@@ -74,27 +39,27 @@
# define CERASE 127
#endif
#ifndef CKILL
-# define CKILL Control ('u')
+# define CKILL Control('u')
#endif
#ifndef CEOF
-# define CEOF Control ('d')
+# define CEOF Control('d')
#endif
#ifndef CEOL
# define CEOL _POSIX_VDISABLE
#endif
#ifndef CSTART
-# define CSTART Control ('q')
+# define CSTART Control('q')
#endif
#ifndef CSTOP
-# define CSTOP Control ('s')
+# define CSTOP Control('s')
#endif
#ifndef CSUSP
-# define CSUSP Control ('z')
+# define CSUSP Control('z')
#endif
#if defined(VEOL2) && !defined(CEOL2)
# define CEOL2 _POSIX_VDISABLE
#endif
-/* ISC renamed swtch to susp for termios, but we'll accept either name. */
+/* ISC renamed swtch to susp for termios, but we'll accept either name */
#if defined(VSUSP) && !defined(VSWTCH)
# define VSWTCH VSUSP
# define CSWTCH CSUSP
@@ -103,30 +68,30 @@
# define CSWTCH _POSIX_VDISABLE
#endif
-/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
- So the default is to disable `swtch.' */
-#if defined (__sparc__) && defined (__svr4__)
+/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
+ So the default is to disable 'swtch.' */
+#if defined(__sparc__) && defined(__svr4__)
# undef CSWTCH
# define CSWTCH _POSIX_VDISABLE
#endif
-#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
+#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
# define VWERASE VWERSE
#endif
-#if defined(VDSUSP) && !defined (CDSUSP)
-# define CDSUSP Control ('y')
+#if defined(VDSUSP) && !defined(CDSUSP)
+# define CDSUSP Control('y')
#endif
#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
# define VREPRINT VRPRNT
#endif
#if defined(VREPRINT) && !defined(CRPRNT)
-# define CRPRNT Control ('r')
+# define CRPRNT Control('r')
#endif
#if defined(VWERASE) && !defined(CWERASE)
-# define CWERASE Control ('w')
+# define CWERASE Control('w')
#endif
#if defined(VLNEXT) && !defined(CLNEXT)
-# define CLNEXT Control ('v')
+# define CLNEXT Control('v')
#endif
#if defined(VDISCARD) && !defined(VFLUSHO)
# define VFLUSHO VDISCARD
@@ -144,816 +109,639 @@
# define ECHOKE CRTKIL
#endif
#if defined(VFLUSHO) && !defined(CFLUSHO)
-# define CFLUSHO Control ('o')
+# define CFLUSHO Control('o')
#endif
#if defined(VSTATUS) && !defined(CSTATUS)
-# define CSTATUS Control ('t')
+# define CSTATUS Control('t')
#endif
-/* Which speeds to set. */
+/* Which speeds to set */
enum speed_setting {
input_speed, output_speed, both_speeds
};
-/* Which member(s) of `struct termios' a mode uses. */
-enum mode_type {
+/* Which member(s) of 'struct termios' a mode uses */
+enum {
/* Do NOT change the order or values, as mode_type_flag()
- * depends on them. */
+ * depends on them */
control, input, output, local, combination
};
+/* Flags for 'struct mode_info' */
+#define SANE_SET 1 /* Set in 'sane' mode */
+#define SANE_UNSET 2 /* Unset in 'sane' mode */
+#define REV 4 /* Can be turned off by prepending '-' */
+#define OMIT 8 /* Don't display value */
+
-static const char evenp [] = "evenp";
-static const char raw [] = "raw";
-static const char stty_min [] = "min";
-static const char stty_time [] = "time";
-static const char stty_swtch[] = "swtch";
-static const char stty_eol [] = "eol";
-static const char stty_eof [] = "eof";
-static const char parity [] = "parity";
-static const char stty_oddp [] = "oddp";
-static const char stty_nl [] = "nl";
-static const char stty_ek [] = "ek";
-static const char stty_sane [] = "sane";
-static const char cbreak [] = "cbreak";
-static const char stty_pass8[] = "pass8";
-static const char litout [] = "litout";
-static const char cooked [] = "cooked";
-static const char decctlq [] = "decctlq";
-static const char stty_tabs [] = "tabs";
-static const char stty_lcase[] = "lcase";
-static const char stty_LCASE[] = "LCASE";
-static const char stty_crt [] = "crt";
-static const char stty_dec [] = "dec";
-
-
-/* Flags for `struct mode_info'. */
-#define SANE_SET 1 /* Set in `sane' mode. */
-#define SANE_UNSET 2 /* Unset in `sane' mode. */
-#define REV 4 /* Can be turned off by prepending `-'. */
-#define OMIT 8 /* Don't display value. */
-
-/* Each mode. */
+/* Each mode.
+ * This structure should be kept as small as humanly possible.
+ */
struct mode_info {
- const char *name; /* Name given on command line. */
- /* enum mode_type type; */
- char type; /* Which structure element to change. */
- char flags; /* Setting and display options. */
- unsigned short mask; /* Other bits to turn off for this mode. */
- unsigned long bits; /* Bits to set for this mode. */
+ const uint8_t type; /* Which structure element to change */
+ const uint8_t flags; /* Setting and display options */
+ /* only these values are ever used, so... */
+#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
+ const uint8_t mask;
+#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
+ const uint16_t mask;
+#else
+ const tcflag_t mask; /* Other bits to turn off for this mode */
+#endif
+ /* was using short here, but ppc32 was unhappy */
+ const tcflag_t bits; /* Bits to set for this mode */
+};
+
+enum {
+ /* Must match mode_name[] and mode_info[] order! */
+ IDX_evenp = 0,
+ IDX_parity,
+ IDX_oddp,
+ IDX_nl,
+ IDX_ek,
+ IDX_sane,
+ IDX_cooked,
+ IDX_raw,
+ IDX_pass8,
+ IDX_litout,
+ IDX_cbreak,
+ IDX_crt,
+ IDX_dec,
+#ifdef IXANY
+ IDX_decctlq,
+#endif
+#if defined(TABDLY) || defined(OXTABS)
+ IDX_tabs,
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+ IDX_lcase,
+ IDX_LCASE,
+#endif
};
-#define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
-
-static const struct mode_info mode_info[] = {
- MI_ENTRY("parenb", control, REV, PARENB, 0 ),
- MI_ENTRY("parodd", control, REV, PARODD, 0 ),
- MI_ENTRY("cs5", control, 0, CS5, CSIZE),
- MI_ENTRY("cs6", control, 0, CS6, CSIZE),
- MI_ENTRY("cs7", control, 0, CS7, CSIZE),
- MI_ENTRY("cs8", control, 0, CS8, CSIZE),
- MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
- MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
- MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
- MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
- MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
+#define MI_ENTRY(N,T,F,B,M) N "\0"
+
+/* Mode names given on command line */
+static const char mode_name[] =
+ MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("ek", combination, OMIT, 0, 0 )
+ MI_ENTRY("sane", combination, OMIT, 0, 0 )
+ MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("crt", combination, OMIT, 0, 0 )
+ MI_ENTRY("dec", combination, OMIT, 0, 0 )
+#ifdef IXANY
+ MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(TABDLY) || defined(OXTABS)
+ MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
+#endif
+#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
+ MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
+#endif
+ MI_ENTRY("parenb", control, REV, PARENB, 0 )
+ MI_ENTRY("parodd", control, REV, PARODD, 0 )
+ MI_ENTRY("cs5", control, 0, CS5, CSIZE)
+ MI_ENTRY("cs6", control, 0, CS6, CSIZE)
+ MI_ENTRY("cs7", control, 0, CS7, CSIZE)
+ MI_ENTRY("cs8", control, 0, CS8, CSIZE)
+ MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
+ MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
+ MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
+ MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
+ MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
#ifdef CRTSCTS
- MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
-#endif
- MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
- MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
- MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
- MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
- MI_ENTRY("inpck", input, REV, INPCK, 0 ),
- MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
- MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
- MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
- MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
- MI_ENTRY("ixon", input, REV, IXON, 0 ),
- MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
- MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
+ MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
+#endif
+ MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
+ MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
+ MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
+ MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
+ MI_ENTRY("inpck", input, REV, INPCK, 0 )
+ MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
+ MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
+ MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
+ MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
+ MI_ENTRY("ixon", input, REV, IXON, 0 )
+ MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
+ MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
#ifdef IUCLC
- MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
+ MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
#endif
#ifdef IXANY
- MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
+ MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
#endif
#ifdef IMAXBEL
- MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
+ MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
#endif
- MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
+ MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
#ifdef OLCUC
- MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
+ MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
#endif
#ifdef OCRNL
- MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
+ MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
#endif
#ifdef ONLCR
- MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
+ MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
#endif
#ifdef ONOCR
- MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
+ MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
#endif
#ifdef ONLRET
- MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
+ MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
#endif
#ifdef OFILL
- MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
+ MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
#endif
#ifdef OFDEL
- MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
+ MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
#endif
#ifdef NLDLY
- MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
- MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
+ MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
+ MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
#endif
#ifdef CRDLY
- MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
- MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
- MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
- MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
+ MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
+ MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
+ MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
+ MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
#endif
#ifdef TABDLY
- MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
- MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
- MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
- MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
+ MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
+ MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
+ MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
+ MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
#else
# ifdef OXTABS
- MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
+ MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
# endif
#endif
#ifdef BSDLY
- MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
- MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
+ MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
+ MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
#endif
#ifdef VTDLY
- MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
- MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
+ MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
+ MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
#endif
#ifdef FFDLY
- MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
- MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
+ MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
+ MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
#endif
- MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
- MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
+ MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
+ MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
#ifdef IEXTEN
- MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
-#endif
- MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
- MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
- MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
- MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
- MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
- MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
+ MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
+#endif
+ MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
+ MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
+ MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
+ MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
+ MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
+ MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
#ifdef XCASE
- MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
+ MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
#endif
#ifdef TOSTOP
- MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
+ MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
#endif
#ifdef ECHOPRT
- MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
- MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
+ MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
+ MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
#endif
#ifdef ECHOCTL
- MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
- MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
+ MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
+ MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
#endif
#ifdef ECHOKE
- MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
- MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
-#endif
- MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
- MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
- MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
+ MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
+ MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
+#endif
+ ;
+
+#undef MI_ENTRY
+#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
+
+static const struct mode_info mode_info[] = {
+ /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
+ MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("ek", combination, OMIT, 0, 0 )
+ MI_ENTRY("sane", combination, OMIT, 0, 0 )
+ MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("crt", combination, OMIT, 0, 0 )
+ MI_ENTRY("dec", combination, OMIT, 0, 0 )
#ifdef IXANY
- MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
+ MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
#endif
-#if defined (TABDLY) || defined (OXTABS)
- MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
+#if defined(TABDLY) || defined(OXTABS)
+ MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
#endif
#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
- MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
- MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
+ MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
+ MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
+#endif
+ MI_ENTRY("parenb", control, REV, PARENB, 0 )
+ MI_ENTRY("parodd", control, REV, PARODD, 0 )
+ MI_ENTRY("cs5", control, 0, CS5, CSIZE)
+ MI_ENTRY("cs6", control, 0, CS6, CSIZE)
+ MI_ENTRY("cs7", control, 0, CS7, CSIZE)
+ MI_ENTRY("cs8", control, 0, CS8, CSIZE)
+ MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
+ MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
+ MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
+ MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
+ MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
+#ifdef CRTSCTS
+ MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
+#endif
+ MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
+ MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
+ MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
+ MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
+ MI_ENTRY("inpck", input, REV, INPCK, 0 )
+ MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
+ MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
+ MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
+ MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
+ MI_ENTRY("ixon", input, REV, IXON, 0 )
+ MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
+ MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
+#ifdef IUCLC
+ MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
+#endif
+#ifdef IXANY
+ MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
+#endif
+#ifdef IMAXBEL
+ MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
+#endif
+ MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
+#ifdef OLCUC
+ MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
+#endif
+#ifdef OCRNL
+ MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
+#endif
+#ifdef ONLCR
+ MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
+#endif
+#ifdef ONOCR
+ MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
+#endif
+#ifdef ONLRET
+ MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
+#endif
+#ifdef OFILL
+ MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
+#endif
+#ifdef OFDEL
+ MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
+#endif
+#ifdef NLDLY
+ MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
+ MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
+#endif
+#ifdef CRDLY
+ MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
+ MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
+ MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
+ MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
+#endif
+
+#ifdef TABDLY
+ MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
+ MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
+ MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
+ MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
+#else
+# ifdef OXTABS
+ MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
+# endif
+#endif
+
+#ifdef BSDLY
+ MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
+ MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
+#endif
+#ifdef VTDLY
+ MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
+ MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
+#endif
+#ifdef FFDLY
+ MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
+ MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
+#endif
+ MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
+ MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
+#ifdef IEXTEN
+ MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
+#endif
+ MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
+ MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
+ MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
+ MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
+ MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
+ MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
+#ifdef XCASE
+ MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
+#endif
+#ifdef TOSTOP
+ MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
+#endif
+#ifdef ECHOPRT
+ MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
+ MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
+#endif
+#ifdef ECHOCTL
+ MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
+ MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
+#endif
+#ifdef ECHOKE
+ MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
+ MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
#endif
- MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
- MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
};
-static const int NUM_mode_info =
+enum {
+ NUM_mode_info = ARRAY_SIZE(mode_info)
+};
- (sizeof(mode_info) / sizeof(struct mode_info));
-/* Control character settings. */
+/* Control characters */
struct control_info {
- const char *name; /* Name given on command line. */
- unsigned char saneval; /* Value to set for `stty sane'. */
- unsigned char offset; /* Offset in c_cc. */
+ const uint8_t saneval; /* Value to set for 'stty sane' */
+ const uint8_t offset; /* Offset in c_cc */
};
-/* Control characters. */
-
-static const struct control_info control_info[] = {
- {"intr", CINTR, VINTR},
- {"quit", CQUIT, VQUIT},
- {"erase", CERASE, VERASE},
- {"kill", CKILL, VKILL},
- {stty_eof, CEOF, VEOF},
- {stty_eol, CEOL, VEOL},
+enum {
+ /* Must match control_name[] and control_info[] order! */
+ CIDX_intr = 0,
+ CIDX_quit,
+ CIDX_erase,
+ CIDX_kill,
+ CIDX_eof,
+ CIDX_eol,
#ifdef VEOL2
- {"eol2", CEOL2, VEOL2},
+ CIDX_eol2,
#endif
#ifdef VSWTCH
- {stty_swtch, CSWTCH, VSWTCH},
+ CIDX_swtch,
#endif
- {"start", CSTART, VSTART},
- {"stop", CSTOP, VSTOP},
- {"susp", CSUSP, VSUSP},
+ CIDX_start,
+ CIDX_stop,
+ CIDX_susp,
#ifdef VDSUSP
- {"dsusp", CDSUSP, VDSUSP},
+ CIDX_dsusp,
#endif
#ifdef VREPRINT
- {"rprnt", CRPRNT, VREPRINT},
+ CIDX_rprnt,
#endif
#ifdef VWERASE
- {"werase", CWERASE, VWERASE},
+ CIDX_werase,
#endif
#ifdef VLNEXT
- {"lnext", CLNEXT, VLNEXT},
+ CIDX_lnext,
#endif
#ifdef VFLUSHO
- {"flush", CFLUSHO, VFLUSHO},
+ CIDX_flush,
#endif
#ifdef VSTATUS
- {"status", CSTATUS, VSTATUS},
+ CIDX_status,
#endif
- /* These must be last because of the display routines. */
- {stty_min, 1, VMIN},
- {stty_time, 0, VTIME},
+ CIDX_min,
+ CIDX_time,
};
-static const int NUM_control_info =
- (sizeof(control_info) / sizeof(struct control_info));
-
-
-static const char * visible(unsigned int ch);
-static int recover_mode(char *arg, struct termios *mode);
-static int screen_columns(void);
-static int set_mode(const struct mode_info *info,
- int reversed, struct termios *mode);
-static speed_t string_to_baud(const char *arg);
-static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
-static void display_all(struct termios *mode, int fd);
-static void display_changed(struct termios *mode, int fd);
-static void display_recoverable(struct termios *mode, int fd);
-static void display_speed(struct termios *mode, int fancy);
-static void display_window_size(int fancy, int fd);
-static void sane_mode(struct termios *mode);
-static void set_control_char(const struct control_info *info,
- const char *arg, struct termios *mode);
-static void set_speed(enum speed_setting type,
- const char *arg, struct termios *mode);
-static void set_window_size(int rows, int cols, int fd);
-
-static const char *device_name;
-
-static __attribute__ ((noreturn)) void perror_on_device(const char *fmt)
-{
- bb_perror_msg_and_die(fmt, device_name);
-}
-
-
-/* The width of the screen, for output wrapping. */
-static int max_col;
-
-/* Current position, to know when to wrap. */
-static int current_col;
-
-/* Print format string MESSAGE and optional args.
- Wrap to next line first if it won't fit.
- Print a space first unless MESSAGE will start a new line. */
-
-static void wrapf(const char *message, ...)
-{
- va_list args;
- char buf[1024]; /* Plenty long for our needs. */
- int buflen;
-
- va_start(args, message);
- vsprintf(buf, message, args);
- va_end(args);
- buflen = strlen(buf);
- if (current_col + (current_col > 0) + buflen >= max_col) {
- putchar('\n');
- current_col = 0;
- }
- if (current_col > 0) {
- putchar(' ');
- current_col++;
- }
- fputs(buf, stdout);
- current_col += buflen;
-}
-
-static const struct suffix_mult stty_suffixes[] = {
- {"b", 512 },
- {"k", 1024},
- {"B", 1024},
- {NULL, 0 }
-};
-
-#ifndef TEST
-extern int stty_main(int argc, char **argv)
-#else
-extern int main(int argc, char **argv)
-#endif
-{
- struct termios mode;
- void (*output_func)(struct termios *, int);
- int optc;
- int require_set_attr;
- int speed_was_set;
- int verbose_output;
- int recoverable_output;
- int k;
- int noargs = 1;
- char * file_name = NULL;
- int fd;
-
-
- output_func = display_changed;
- verbose_output = 0;
- recoverable_output = 0;
-
- /* Don't print error messages for unrecognized options. */
- opterr = 0;
-
- while ((optc = getopt(argc, argv, "agF:")) != -1) {
- switch (optc) {
- case 'a':
- verbose_output = 1;
- output_func = display_all;
- break;
-
- case 'g':
- recoverable_output = 1;
- output_func = display_recoverable;
- break;
-
- case 'F':
- if (file_name)
- bb_error_msg_and_die("only one device may be specified");
- file_name = optarg;
- break;
-
- default: /* unrecognized option */
- noargs = 0;
- break;
- }
-
- if (noargs == 0)
- break;
- }
-
- if (optind < argc)
- noargs = 0;
-
- /* Specifying both -a and -g gets an error. */
- if (verbose_output & recoverable_output)
- bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
-
- /* Specifying any other arguments with -a or -g gets an error. */
- if (~noargs & (verbose_output | recoverable_output))
- bb_error_msg_and_die ("modes may not be set when specifying an output style");
-
- /* FIXME: it'd be better not to open the file until we've verified
- that all arguments are valid. Otherwise, we could end up doing
- only some of the requested operations and then failing, probably
- leaving things in an undesirable state. */
-
- if (file_name) {
- int fdflags;
-
- device_name = file_name;
- fd = bb_xopen(device_name, O_RDONLY | O_NONBLOCK);
- if ((fdflags = fcntl(fd, F_GETFL)) == -1
- || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
- perror_on_device("%s: couldn't reset non-blocking mode");
- } else {
- fd = 0;
- device_name = bb_msg_standard_input;
- }
-
- /* Initialize to all zeroes so there is no risk memcmp will report a
- spurious difference in an uninitialized portion of the structure. */
- memset(&mode, 0, sizeof(mode));
- if (tcgetattr(fd, &mode))
- perror_on_device("%s");
-
- if (verbose_output | recoverable_output | noargs) {
- max_col = screen_columns();
- current_col = 0;
- output_func(&mode, fd);
- return EXIT_SUCCESS;
- }
-
- speed_was_set = 0;
- require_set_attr = 0;
- k = 0;
- while (++k < argc) {
- int match_found = 0;
- int reversed = 0;
- int i;
-
- if (argv[k][0] == '-') {
- char *find_dev_opt;
-
- ++argv[k];
-
- /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
- Find the options that have been parsed. This is really
- gross, but it's needed because stty SETTINGS look like options to
- getopt(), so we need to work around things in a really horrible
- way. If any new options are ever added to stty, the short option
- MUST NOT be a letter which is the first letter of one of the
- possible stty settings.
- */
- find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
- if(find_dev_opt) {
- if(find_dev_opt[1]==0) /* -*F /dev/foo */
- k++; /* skip /dev/foo */
- continue; /* else -*F/dev/foo - no skip */
- }
- if(argv[k][0]=='a' || argv[k][0]=='g')
- continue;
- /* Is not options - is reverse params */
- reversed = 1;
- }
- for (i = 0; i < NUM_mode_info; ++i)
- if (STREQ(argv[k], mode_info[i].name)) {
- match_found = set_mode(&mode_info[i], reversed, &mode);
- require_set_attr = 1;
- break;
- }
-
- if (match_found == 0 && reversed)
- bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
-
- if (match_found == 0)
- for (i = 0; i < NUM_control_info; ++i)
- if (STREQ(argv[k], control_info[i].name)) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- match_found = 1;
- ++k;
- set_control_char(&control_info[i], argv[k], &mode);
- require_set_attr = 1;
- break;
- }
-
- if (match_found == 0) {
- if (STREQ(argv[k], "ispeed")) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- ++k;
- set_speed(input_speed, argv[k], &mode);
- speed_was_set = 1;
- require_set_attr = 1;
- } else if (STREQ(argv[k], "ospeed")) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- ++k;
- set_speed(output_speed, argv[k], &mode);
- speed_was_set = 1;
- require_set_attr = 1;
- }
-#ifdef TIOCGWINSZ
- else if (STREQ(argv[k], "rows")) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- ++k;
- set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
- -1, fd);
- } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- ++k;
- set_window_size(-1,
- (int) bb_xparse_number(argv[k], stty_suffixes),
- fd);
- } else if (STREQ(argv[k], "size")) {
- max_col = screen_columns();
- current_col = 0;
- display_window_size(0, fd);
- }
-#endif
-#ifdef HAVE_C_LINE
- else if (STREQ(argv[k], "line")) {
- if (k == argc - 1)
- bb_error_msg_and_die("missing argument to `%s'", argv[k]);
- ++k;
- mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
- require_set_attr = 1;
- }
-#endif
- else if (STREQ(argv[k], "speed")) {
- max_col = screen_columns();
- display_speed(&mode, 0);
- } else if (recover_mode(argv[k], &mode) == 1)
- require_set_attr = 1;
- else if (string_to_baud(argv[k]) != (speed_t) - 1) {
- set_speed(both_speeds, argv[k], &mode);
- speed_was_set = 1;
- require_set_attr = 1;
- } else
- bb_error_msg_and_die("invalid argument `%s'", argv[k]);
- }
- }
+#define CI_ENTRY(n,s,o) n "\0"
- if (require_set_attr) {
- struct termios new_mode;
-
- if (tcsetattr(fd, TCSADRAIN, &mode))
- perror_on_device("%s");
-
- /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
- it performs *any* of the requested operations. This means it
- can report `success' when it has actually failed to perform
- some proper subset of the requested operations. To detect
- this partial failure, get the current terminal attributes and
- compare them to the requested ones. */
-
- /* Initialize to all zeroes so there is no risk memcmp will report a
- spurious difference in an uninitialized portion of the structure. */
- memset(&new_mode, 0, sizeof(new_mode));
- if (tcgetattr(fd, &new_mode))
- perror_on_device("%s");
-
- /* Normally, one shouldn't use memcmp to compare structures that
- may have `holes' containing uninitialized data, but we have been
- careful to initialize the storage of these two variables to all
- zeroes. One might think it more efficient simply to compare the
- modified fields, but that would require enumerating those fields --
- and not all systems have the same fields in this structure. */
-
- if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
-#ifdef CIBAUD
- /* SunOS 4.1.3 (at least) has the problem that after this sequence,
- tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
- sometimes (m1 != m2). The only difference is in the four bits
- of the c_cflag field corresponding to the baud rate. To save
- Sun users a little confusion, don't report an error if this
- happens. But suppress the error only if we haven't tried to
- set the baud rate explicitly -- otherwise we'd never give an
- error for a true failure to set the baud rate. */
-
- new_mode.c_cflag &= (~CIBAUD);
- if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
+/* Name given on command line */
+static const char control_name[] =
+ CI_ENTRY("intr", CINTR, VINTR )
+ CI_ENTRY("quit", CQUIT, VQUIT )
+ CI_ENTRY("erase", CERASE, VERASE )
+ CI_ENTRY("kill", CKILL, VKILL )
+ CI_ENTRY("eof", CEOF, VEOF )
+ CI_ENTRY("eol", CEOL, VEOL )
+#ifdef VEOL2
+ CI_ENTRY("eol2", CEOL2, VEOL2 )
#endif
- perror_on_device ("%s: unable to perform all requested operations");
- }
- }
-
- return EXIT_SUCCESS;
-}
-
-/* Return 0 if not applied because not reversible; otherwise return 1. */
-
-static int
-set_mode(const struct mode_info *info, int reversed, struct termios *mode)
-{
- tcflag_t *bitsp;
-
- if (reversed && (info->flags & REV) == 0)
- return 0;
-
- bitsp = mode_type_flag(info->type, mode);
-
- if (bitsp == NULL) {
- /* Combination mode. */
- if (info->name == evenp || info->name == parity) {
- if (reversed)
- mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
- else
- mode->c_cflag =
- (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
- } else if (info->name == stty_oddp) {
- if (reversed)
- mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
- else
- mode->c_cflag =
- (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
- } else if (info->name == stty_nl) {
- if (reversed) {
- mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
- mode->c_oflag = (mode->c_oflag
-#ifdef ONLCR
- | ONLCR
+#ifdef VSWTCH
+ CI_ENTRY("swtch", CSWTCH, VSWTCH )
#endif
- )
-#ifdef OCRNL
- & ~OCRNL
+ CI_ENTRY("start", CSTART, VSTART )
+ CI_ENTRY("stop", CSTOP, VSTOP )
+ CI_ENTRY("susp", CSUSP, VSUSP )
+#ifdef VDSUSP
+ CI_ENTRY("dsusp", CDSUSP, VDSUSP )
#endif
-#ifdef ONLRET
- & ~ONLRET
+#ifdef VREPRINT
+ CI_ENTRY("rprnt", CRPRNT, VREPRINT)
#endif
- ;
- } else {
- mode->c_iflag = mode->c_iflag & ~ICRNL;
-#ifdef ONLCR
- mode->c_oflag = mode->c_oflag & ~ONLCR;
+#ifdef VWERASE
+ CI_ENTRY("werase", CWERASE, VWERASE )
#endif
- }
- } else if (info->name == stty_ek) {
- mode->c_cc[VERASE] = CERASE;
- mode->c_cc[VKILL] = CKILL;
- } else if (info->name == stty_sane)
- sane_mode(mode);
- else if (info->name == cbreak) {
- if (reversed)
- mode->c_lflag |= ICANON;
- else
- mode->c_lflag &= ~ICANON;
- } else if (info->name == stty_pass8) {
- if (reversed) {
- mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
- mode->c_iflag |= ISTRIP;
- } else {
- mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
- mode->c_iflag &= ~ISTRIP;
- }
- } else if (info->name == litout) {
- if (reversed) {
- mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
- mode->c_iflag |= ISTRIP;
- mode->c_oflag |= OPOST;
- } else {
- mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
- mode->c_iflag &= ~ISTRIP;
- mode->c_oflag &= ~OPOST;
- }
- } else if (info->name == raw || info->name == cooked) {
- if ((info->name[0] == 'r' && reversed)
- || (info->name[0] == 'c' && !reversed)) {
- /* Cooked mode. */
- mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
- mode->c_oflag |= OPOST;
- mode->c_lflag |= ISIG | ICANON;
-#if VMIN == VEOF
- mode->c_cc[VEOF] = CEOF;
+#ifdef VLNEXT
+ CI_ENTRY("lnext", CLNEXT, VLNEXT )
#endif
-#if VTIME == VEOL
- mode->c_cc[VEOL] = CEOL;
+#ifdef VFLUSHO
+ CI_ENTRY("flush", CFLUSHO, VFLUSHO )
#endif
- } else {
- /* Raw mode. */
- mode->c_iflag = 0;
- mode->c_oflag &= ~OPOST;
- mode->c_lflag &= ~(ISIG | ICANON
-#ifdef XCASE
- | XCASE
+#ifdef VSTATUS
+ CI_ENTRY("status", CSTATUS, VSTATUS )
+#endif
+ /* These must be last because of the display routines */
+ CI_ENTRY("min", 1, VMIN )
+ CI_ENTRY("time", 0, VTIME )
+ ;
+
+#undef CI_ENTRY
+#define CI_ENTRY(n,s,o) { s, o },
+
+static const struct control_info control_info[] = {
+ /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
+ CI_ENTRY("intr", CINTR, VINTR )
+ CI_ENTRY("quit", CQUIT, VQUIT )
+ CI_ENTRY("erase", CERASE, VERASE )
+ CI_ENTRY("kill", CKILL, VKILL )
+ CI_ENTRY("eof", CEOF, VEOF )
+ CI_ENTRY("eol", CEOL, VEOL )
+#ifdef VEOL2
+ CI_ENTRY("eol2", CEOL2, VEOL2 )
#endif
- );
- mode->c_cc[VMIN] = 1;
- mode->c_cc[VTIME] = 0;
- }
- }
-#ifdef IXANY
- else if (info->name == decctlq) {
- if (reversed)
- mode->c_iflag |= IXANY;
- else
- mode->c_iflag &= ~IXANY;
- }
+#ifdef VSWTCH
+ CI_ENTRY("swtch", CSWTCH, VSWTCH )
#endif
-#ifdef TABDLY
- else if (info->name == stty_tabs) {
- if (reversed)
- mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
- else
- mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
- }
-#else
-# ifdef OXTABS
- else if (info->name == stty_tabs) {
- if (reversed)
- mode->c_oflag = mode->c_oflag | OXTABS;
- else
- mode->c_oflag = mode->c_oflag & ~OXTABS;
- }
-# endif
+ CI_ENTRY("start", CSTART, VSTART )
+ CI_ENTRY("stop", CSTOP, VSTOP )
+ CI_ENTRY("susp", CSUSP, VSUSP )
+#ifdef VDSUSP
+ CI_ENTRY("dsusp", CDSUSP, VDSUSP )
#endif
-#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
- else if (info->name == stty_lcase || info->name == stty_LCASE) {
- if (reversed) {
- mode->c_lflag &= ~XCASE;
- mode->c_iflag &= ~IUCLC;
- mode->c_oflag &= ~OLCUC;
- } else {
- mode->c_lflag |= XCASE;
- mode->c_iflag |= IUCLC;
- mode->c_oflag |= OLCUC;
- }
- }
+#ifdef VREPRINT
+ CI_ENTRY("rprnt", CRPRNT, VREPRINT)
#endif
- else if (info->name == stty_crt)
- mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
- | ECHOCTL
+#ifdef VWERASE
+ CI_ENTRY("werase", CWERASE, VWERASE )
#endif
-#ifdef ECHOKE
- | ECHOKE
-#endif
- ;
- else if (info->name == stty_dec) {
- mode->c_cc[VINTR] = 3; /* ^C */
- mode->c_cc[VERASE] = 127; /* DEL */
- mode->c_cc[VKILL] = 21; /* ^U */
- mode->c_lflag |= ECHOE
-#ifdef ECHOCTL
- | ECHOCTL
+#ifdef VLNEXT
+ CI_ENTRY("lnext", CLNEXT, VLNEXT )
#endif
-#ifdef ECHOKE
- | ECHOKE
+#ifdef VFLUSHO
+ CI_ENTRY("flush", CFLUSHO, VFLUSHO )
#endif
- ;
-#ifdef IXANY
- mode->c_iflag &= ~IXANY;
+#ifdef VSTATUS
+ CI_ENTRY("status", CSTATUS, VSTATUS )
#endif
- }
- } else if (reversed)
- *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
- else
- *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
+ /* These must be last because of the display routines */
+ CI_ENTRY("min", 1, VMIN )
+ CI_ENTRY("time", 0, VTIME )
+};
- return 1;
+enum {
+ NUM_control_info = ARRAY_SIZE(control_info)
+};
+
+
+struct globals {
+ const char *device_name; // = bb_msg_standard_input;
+ /* The width of the screen, for output wrapping */
+ unsigned max_col; // = 80;
+ /* Current position, to know when to wrap */
+ unsigned current_col;
+ char buf[10];
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+ G.device_name = bb_msg_standard_input; \
+ G.max_col = 80; \
+} while (0)
+
+
+/* Return a string that is the printable representation of character CH */
+/* Adapted from 'cat' by Torbjorn Granlund */
+static const char *visible(unsigned ch)
+{
+ char *bpout = G.buf;
+
+ if (ch == _POSIX_VDISABLE)
+ return "<undef>";
+
+ if (ch >= 128) {
+ ch -= 128;
+ *bpout++ = 'M';
+ *bpout++ = '-';
+ }
+
+ if (ch < 32) {
+ *bpout++ = '^';
+ *bpout++ = ch + 64;
+ } else if (ch < 127) {
+ *bpout++ = ch;
+ } else {
+ *bpout++ = '^';
+ *bpout++ = '?';
+ }
+
+ *bpout = '\0';
+ return G.buf;
}
-static void
-set_control_char(const struct control_info *info, const char *arg,
- struct termios *mode)
+static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
{
- unsigned char value;
+ static const uint8_t tcflag_offsets[] ALIGN1 = {
+ offsetof(struct termios, c_cflag), /* control */
+ offsetof(struct termios, c_iflag), /* input */
+ offsetof(struct termios, c_oflag), /* output */
+ offsetof(struct termios, c_lflag) /* local */
+ };
- if (info->name == stty_min || info->name == stty_time)
- value = bb_xparse_number(arg, stty_suffixes);
- else if (arg[0] == '\0' || arg[1] == '\0')
- value = arg[0];
- else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
- value = _POSIX_VDISABLE;
- else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
- if (arg[1] == '?')
- value = 127;
- else
- value = arg[1] & ~0140; /* Non-letters get weird results. */
- } else
- value = bb_xparse_number(arg, stty_suffixes);
- mode->c_cc[info->offset] = value;
+ if (type <= local) {
+ return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
+ }
+ return NULL;
}
-static void
-set_speed(enum speed_setting type, const char *arg, struct termios *mode)
+static void set_speed_or_die(enum speed_setting type, const char *const arg,
+ struct termios * const mode)
{
speed_t baud;
- baud = string_to_baud(arg);
+ baud = tty_value_to_baud(xatou(arg));
- if (type != output_speed) { /* either input or both */
+ if (type != output_speed) { /* either input or both */
cfsetispeed(mode, baud);
}
- if (type != input_speed) { /* either output or both */
+ if (type != input_speed) { /* either output or both */
cfsetospeed(mode, baud);
}
}
-#ifdef TIOCGWINSZ
+static NORETURN void perror_on_device_and_die(const char *fmt)
+{
+ bb_perror_msg_and_die(fmt, G.device_name);
+}
-static int get_win_size(int fd, struct winsize *win)
+static void perror_on_device(const char *fmt)
{
- int err = ioctl(fd, TIOCGWINSZ, (char *) win);
+ bb_perror_msg(fmt, G.device_name);
+}
- return err;
+/* Print format string MESSAGE and optional args.
+ Wrap to next line first if it won't fit.
+ Print a space first unless MESSAGE will start a new line */
+static void wrapf(const char *message, ...)
+{
+ char buf[128];
+ va_list args;
+ unsigned buflen;
+
+ va_start(args, message);
+ buflen = vsnprintf(buf, sizeof(buf), message, args);
+ va_end(args);
+ /* We seem to be called only with suitable lengths, but check if
+ somebody failed to adhere to this assumption just to be sure. */
+ if (!buflen || buflen >= sizeof(buf)) return;
+
+ if (G.current_col > 0) {
+ G.current_col++;
+ if (buf[0] != '\n') {
+ if (G.current_col + buflen >= G.max_col) {
+ bb_putchar('\n');
+ G.current_col = 0;
+ } else
+ bb_putchar(' ');
+ }
+ }
+ fputs(buf, stdout);
+ G.current_col += buflen;
+ if (buf[buflen-1] == '\n')
+ G.current_col = 0;
}
-static void
-set_window_size(int rows, int cols, int fd)
+static void set_window_size(const int rows, const int cols)
{
- struct winsize win;
+ struct winsize win = { 0, 0, 0, 0 };
- if (get_win_size(fd, &win)) {
- if (errno != EINVAL)
- perror_on_device("%s");
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
+ if (errno != EINVAL) {
+ goto bail;
+ }
memset(&win, 0, sizeof(win));
}
@@ -962,290 +750,196 @@ set_window_size(int rows, int cols, int fd)
if (cols >= 0)
win.ws_col = cols;
-# ifdef TIOCSSIZE
- /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
- The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
- This comment from sys/ttold.h describes Sun's twisted logic - a better
- test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
- At any rate, the problem is gone in Solaris 2.x. */
-
- if (win.ws_row == 0 || win.ws_col == 0) {
- struct ttysize ttysz;
-
- ttysz.ts_lines = win.ws_row;
- ttysz.ts_cols = win.ws_col;
-
- win.ws_row = win.ws_col = 1;
-
- if ((ioctl(fd, TIOCSWINSZ, (char *) &win) != 0)
- || (ioctl(fd, TIOCSSIZE, (char *) &ttysz) != 0)) {
- perror_on_device("%s");
- return;
- }
-# endif
-
- if (ioctl(fd, TIOCSWINSZ, (char *) &win))
+ if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
+bail:
perror_on_device("%s");
}
-static void display_window_size(int fancy, int fd)
+static void display_window_size(const int fancy)
{
- const char *fmt_str = "%s" "\0" "%s: no size information for this device";
- struct winsize win;
+ const char *fmt_str = "%s\0%s: no size information for this device";
+ unsigned width, height;
- if (get_win_size(fd, &win)) {
+ if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
perror_on_device(fmt_str);
}
} else {
wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
- win.ws_row, win.ws_col);
- if (!fancy)
- current_col = 0;
+ height, width);
}
}
-#endif
-static int screen_columns(void)
+static const struct suffix_mult stty_suffixes[] = {
+ { "b", 512 },
+ { "k", 1024 },
+ { "B", 1024 },
+ { }
+};
+
+static const struct mode_info *find_mode(const char *name)
{
- int columns;
- const char *s;
+ int i = index_in_strings(mode_name, name);
+ return i >= 0 ? &mode_info[i] : NULL;
+}
-#ifdef TIOCGWINSZ
- struct winsize win;
+static const struct control_info *find_control(const char *name)
+{
+ int i = index_in_strings(control_name, name);
+ return i >= 0 ? &control_info[i] : NULL;
+}
- /* With Solaris 2.[123], this ioctl fails and errno is set to
- EINVAL for telnet (but not rlogin) sessions.
- On ISC 3.0, it fails for the console and the serial port
- (but it works for ptys).
- It can also fail on any system when stdout isn't a tty.
- In case of any failure, just use the default. */
- if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
- return win.ws_col;
-#endif
+enum {
+ param_need_arg = 0x80,
+ param_line = 1 | 0x80,
+ param_rows = 2 | 0x80,
+ param_cols = 3 | 0x80,
+ param_columns = 4 | 0x80,
+ param_size = 5,
+ param_speed = 6,
+ param_ispeed = 7 | 0x80,
+ param_ospeed = 8 | 0x80,
+};
- columns = 80;
- if ((s = getenv("COLUMNS"))) {
- columns = atoi(s);
- }
- return columns;
+static int find_param(const char *const name)
+{
+ static const char params[] ALIGN1 =
+ "line\0" /* 1 */
+ "rows\0" /* 2 */
+ "cols\0" /* 3 */
+ "columns\0" /* 4 */
+ "size\0" /* 5 */
+ "speed\0" /* 6 */
+ "ispeed\0"
+ "ospeed\0";
+ int i = index_in_strings(params, name) + 1;
+ if (i == 0)
+ return 0;
+ if (i != 5 && i != 6)
+ i |= 0x80;
+ return i;
}
-static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
+static int recover_mode(const char *arg, struct termios *mode)
{
- static const unsigned char tcflag_offsets[] = {
- offsetof(struct termios, c_cflag), /* control */
- offsetof(struct termios, c_iflag), /* input */
- offsetof(struct termios, c_oflag), /* output */
- offsetof(struct termios, c_lflag) /* local */
- };
+ int i, n;
+ unsigned chr;
+ unsigned long iflag, oflag, cflag, lflag;
- if (((unsigned int) type) <= local) {
- return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
+ /* Scan into temporaries since it is too much trouble to figure out
+ the right format for 'tcflag_t' */
+ if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
+ &iflag, &oflag, &cflag, &lflag, &n) != 4)
+ return 0;
+ mode->c_iflag = iflag;
+ mode->c_oflag = oflag;
+ mode->c_cflag = cflag;
+ mode->c_lflag = lflag;
+ arg += n;
+ for (i = 0; i < NCCS; ++i) {
+ if (sscanf(arg, ":%x%n", &chr, &n) != 1)
+ return 0;
+ mode->c_cc[i] = chr;
+ arg += n;
}
- return NULL;
+
+ /* Fail if there are too many fields */
+ if (*arg != '\0')
+ return 0;
+
+ return 1;
}
-static void display_changed(struct termios *mode, int fd)
+static void display_recoverable(const struct termios *mode,
+ int UNUSED_PARAM dummy)
{
int i;
- int empty_line;
- tcflag_t *bitsp;
- unsigned long mask;
- enum mode_type prev_type = control;
-
- display_speed(mode, 1);
-#ifdef HAVE_C_LINE
- wrapf("line = %d;", mode->c_line);
-#endif
- putchar('\n');
- current_col = 0;
-
- empty_line = 1;
- for (i = 0; control_info[i].name != stty_min; ++i) {
- if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
- continue;
- /* If swtch is the same as susp, don't print both. */
-#if VSWTCH == VSUSP
- if (control_info[i].name == stty_swtch)
- continue;
-#endif
- /* If eof uses the same slot as min, only print whichever applies. */
-#if VEOF == VMIN
- if ((mode->c_lflag & ICANON) == 0
- && (control_info[i].name == stty_eof
- || control_info[i].name == stty_eol)) continue;
-#endif
+ printf("%lx:%lx:%lx:%lx",
+ (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
+ (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
+ for (i = 0; i < NCCS; ++i)
+ printf(":%x", (unsigned int) mode->c_cc[i]);
+ bb_putchar('\n');
+}
- empty_line = 0;
- wrapf("%s = %s;", control_info[i].name,
- visible(mode->c_cc[control_info[i].offset]));
- }
- if ((mode->c_lflag & ICANON) == 0) {
- wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
- (int) mode->c_cc[VTIME]);
- } else if (empty_line == 0)
- putchar('\n');
- current_col = 0;
-
- empty_line = 1;
- for (i = 0; i < NUM_mode_info; ++i) {
- if (mode_info[i].flags & OMIT)
- continue;
- if (mode_info[i].type != prev_type) {
- if (empty_line == 0) {
- putchar('\n');
- current_col = 0;
- empty_line = 1;
- }
- prev_type = mode_info[i].type;
- }
+static void display_speed(const struct termios *mode, int fancy)
+{
+ //01234567 8 9
+ const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
+ unsigned long ispeed, ospeed;
- bitsp = mode_type_flag(mode_info[i].type, mode);
- mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
- if ((*bitsp & mask) == mode_info[i].bits) {
- if (mode_info[i].flags & SANE_UNSET) {
- wrapf("%s", mode_info[i].name);
- empty_line = 0;
- }
- }
- else if ((mode_info[i].flags & (SANE_SET | REV)) ==
- (SANE_SET | REV)) {
- wrapf("-%s", mode_info[i].name);
- empty_line = 0;
- }
+ ospeed = ispeed = cfgetispeed(mode);
+ if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
+ ispeed = ospeed; /* in case ispeed was 0 */
+ //0123 4 5 6 7 8 9
+ fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
}
- if (empty_line == 0)
- putchar('\n');
- current_col = 0;
+ if (fancy) fmt_str += 9;
+ wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
}
-static void
-display_all(struct termios *mode, int fd)
+static void do_display(const struct termios *mode, const int all)
{
int i;
tcflag_t *bitsp;
unsigned long mask;
- enum mode_type prev_type = control;
+ int prev_type = control;
display_speed(mode, 1);
-#ifdef TIOCGWINSZ
- display_window_size(1, fd);
-#endif
+ if (all)
+ display_window_size(1);
#ifdef HAVE_C_LINE
- wrapf("line = %d;", mode->c_line);
+ wrapf("line = %d;\n", mode->c_line);
+#else
+ wrapf("\n");
#endif
- putchar('\n');
- current_col = 0;
- for (i = 0; control_info[i].name != stty_min; ++i) {
- /* If swtch is the same as susp, don't print both. */
+ for (i = 0; i != CIDX_min; ++i) {
+ /* If swtch is the same as susp, don't print both */
#if VSWTCH == VSUSP
- if (control_info[i].name == stty_swtch)
+ if (i == CIDX_swtch)
continue;
#endif
- /* If eof uses the same slot as min, only print whichever applies. */
+ /* If eof uses the same slot as min, only print whichever applies */
#if VEOF == VMIN
if ((mode->c_lflag & ICANON) == 0
- && (control_info[i].name == stty_eof
- || control_info[i].name == stty_eol)) continue;
+ && (i == CIDX_eof || i == CIDX_eol)
+ ) {
+ continue;
+ }
#endif
- wrapf("%s = %s;", control_info[i].name,
+ wrapf("%s = %s;", nth_string(control_name, i),
visible(mode->c_cc[control_info[i].offset]));
}
#if VEOF == VMIN
if ((mode->c_lflag & ICANON) == 0)
#endif
wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
- if (current_col != 0)
- putchar('\n');
- current_col = 0;
+ if (G.current_col) wrapf("\n");
for (i = 0; i < NUM_mode_info; ++i) {
if (mode_info[i].flags & OMIT)
continue;
if (mode_info[i].type != prev_type) {
- putchar('\n');
- current_col = 0;
+ /* wrapf("\n"); */
+ if (G.current_col) wrapf("\n");
prev_type = mode_info[i].type;
}
bitsp = mode_type_flag(mode_info[i].type, mode);
mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
- if ((*bitsp & mask) == mode_info[i].bits)
- wrapf("%s", mode_info[i].name);
- else if (mode_info[i].flags & REV)
- wrapf("-%s", mode_info[i].name);
- }
- putchar('\n');
- current_col = 0;
-}
-
-static void display_speed(struct termios *mode, int fancy)
-{
- unsigned long ispeed, ospeed;
- const char *fmt_str =
- "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
- "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
-
- ospeed = ispeed = cfgetispeed(mode);
- if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
- ispeed = ospeed; /* in case ispeed was 0 */
- fmt_str += 43;
- }
- if (fancy) {
- fmt_str += 9;
- }
- wrapf(fmt_str, bb_baud_to_value(ispeed), bb_baud_to_value(ospeed));
- if (!fancy)
- current_col = 0;
-}
-
-static void display_recoverable(struct termios *mode, int fd)
-{
- int i;
-
- printf("%lx:%lx:%lx:%lx",
- (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
- (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
- for (i = 0; i < NCCS; ++i)
- printf(":%x", (unsigned int) mode->c_cc[i]);
- putchar('\n');
-}
-
-static int recover_mode(char *arg, struct termios *mode)
-{
- int i, n;
- unsigned int chr;
- unsigned long iflag, oflag, cflag, lflag;
-
- /* Scan into temporaries since it is too much trouble to figure out
- the right format for `tcflag_t'. */
- if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
- &iflag, &oflag, &cflag, &lflag, &n) != 4)
- return 0;
- mode->c_iflag = iflag;
- mode->c_oflag = oflag;
- mode->c_cflag = cflag;
- mode->c_lflag = lflag;
- arg += n;
- for (i = 0; i < NCCS; ++i) {
- if (sscanf(arg, ":%x%n", &chr, &n) != 1)
- return 0;
- mode->c_cc[i] = chr;
- arg += n;
+ if ((*bitsp & mask) == mode_info[i].bits) {
+ if (all || (mode_info[i].flags & SANE_UNSET))
+ wrapf("-%s"+1, nth_string(mode_name, i));
+ } else {
+ if ((all && mode_info[i].flags & REV)
+ || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
+ ) {
+ wrapf("-%s", nth_string(mode_name, i));
+ }
+ }
}
-
- /* Fail if there are too many fields. */
- if (*arg != '\0')
- return 0;
-
- return 1;
-}
-
-static speed_t string_to_baud(const char *arg)
-{
- return bb_value_to_baud(bb_xparse_number(arg, 0));
+ if (G.current_col) wrapf("\n");
}
static void sane_mode(struct termios *mode)
@@ -1255,7 +949,7 @@ static void sane_mode(struct termios *mode)
for (i = 0; i < NUM_control_info; ++i) {
#if VMIN == VEOF
- if (control_info[i].name == stty_min)
+ if (i == CIDX_min)
break;
#endif
mode->c_cc[control_info[i].offset] = control_info[i].saneval;
@@ -1274,40 +968,472 @@ static void sane_mode(struct termios *mode)
}
}
-/* Return a string that is the printable representation of character CH. */
-/* Adapted from `cat' by Torbjorn Granlund. */
+/* Save set_mode from #ifdef forest plague */
+#ifndef ONLCR
+#define ONLCR 0
+#endif
+#ifndef OCRNL
+#define OCRNL 0
+#endif
+#ifndef ONLRET
+#define ONLRET 0
+#endif
+#ifndef XCASE
+#define XCASE 0
+#endif
+#ifndef IXANY
+#define IXANY 0
+#endif
+#ifndef TABDLY
+#define TABDLY 0
+#endif
+#ifndef OXTABS
+#define OXTABS 0
+#endif
+#ifndef IUCLC
+#define IUCLC 0
+#endif
+#ifndef OLCUC
+#define OLCUC 0
+#endif
+#ifndef ECHOCTL
+#define ECHOCTL 0
+#endif
+#ifndef ECHOKE
+#define ECHOKE 0
+#endif
-static const char *visible(unsigned int ch)
+static void set_mode(const struct mode_info *info, int reversed,
+ struct termios *mode)
{
- static char buf[10];
- char *bpout = buf;
+ tcflag_t *bitsp;
- if (ch == _POSIX_VDISABLE) {
- return "<undef>";
- }
+ bitsp = mode_type_flag(info->type, mode);
- if (ch >= 128) {
- ch -= 128;
- *bpout++ = 'M';
- *bpout++ = '-';
+ if (bitsp) {
+ if (reversed)
+ *bitsp = *bitsp & ~info->mask & ~info->bits;
+ else
+ *bitsp = (*bitsp & ~info->mask) | info->bits;
+ return;
}
- if (ch < 32) {
- *bpout++ = '^';
- *bpout++ = ch + 64;
- } else if (ch < 127) {
- *bpout++ = ch;
- } else {
- *bpout++ = '^';
- *bpout++ = '?';
+ /* Combination mode */
+ if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
+ if (reversed)
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ else
+ mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
+ } else if (info == &mode_info[IDX_oddp]) {
+ if (reversed)
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ else
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
+ } else if (info == &mode_info[IDX_nl]) {
+ if (reversed) {
+ mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
+ mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
+ } else {
+ mode->c_iflag = mode->c_iflag & ~ICRNL;
+ if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
+ }
+ } else if (info == &mode_info[IDX_ek]) {
+ mode->c_cc[VERASE] = CERASE;
+ mode->c_cc[VKILL] = CKILL;
+ } else if (info == &mode_info[IDX_sane]) {
+ sane_mode(mode);
+ } else if (info == &mode_info[IDX_cbreak]) {
+ if (reversed)
+ mode->c_lflag |= ICANON;
+ else
+ mode->c_lflag &= ~ICANON;
+ } else if (info == &mode_info[IDX_pass8]) {
+ if (reversed) {
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+ mode->c_iflag |= ISTRIP;
+ } else {
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ mode->c_iflag &= ~ISTRIP;
+ }
+ } else if (info == &mode_info[IDX_litout]) {
+ if (reversed) {
+ mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
+ mode->c_iflag |= ISTRIP;
+ mode->c_oflag |= OPOST;
+ } else {
+ mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
+ mode->c_iflag &= ~ISTRIP;
+ mode->c_oflag &= ~OPOST;
+ }
+ } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
+ if ((info == &mode_info[IDX_raw] && reversed)
+ || (info == &mode_info[IDX_cooked] && !reversed)
+ ) {
+ /* Cooked mode */
+ mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
+ mode->c_oflag |= OPOST;
+ mode->c_lflag |= ISIG | ICANON;
+#if VMIN == VEOF
+ mode->c_cc[VEOF] = CEOF;
+#endif
+#if VTIME == VEOL
+ mode->c_cc[VEOL] = CEOL;
+#endif
+ } else {
+ /* Raw mode */
+ mode->c_iflag = 0;
+ mode->c_oflag &= ~OPOST;
+ mode->c_lflag &= ~(ISIG | ICANON | XCASE);
+ mode->c_cc[VMIN] = 1;
+ mode->c_cc[VTIME] = 0;
+ }
+ }
+ else if (IXANY && info == &mode_info[IDX_decctlq]) {
+ if (reversed)
+ mode->c_iflag |= IXANY;
+ else
+ mode->c_iflag &= ~IXANY;
+ }
+ else if (TABDLY && info == &mode_info[IDX_tabs]) {
+ if (reversed)
+ mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
+ else
+ mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
+ }
+ else if (OXTABS && info == &mode_info[IDX_tabs]) {
+ if (reversed)
+ mode->c_oflag |= OXTABS;
+ else
+ mode->c_oflag &= ~OXTABS;
+ } else
+ if (XCASE && IUCLC && OLCUC
+ && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE])
+ ) {
+ if (reversed) {
+ mode->c_lflag &= ~XCASE;
+ mode->c_iflag &= ~IUCLC;
+ mode->c_oflag &= ~OLCUC;
+ } else {
+ mode->c_lflag |= XCASE;
+ mode->c_iflag |= IUCLC;
+ mode->c_oflag |= OLCUC;
+ }
+ } else if (info == &mode_info[IDX_crt]) {
+ mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
+ } else if (info == &mode_info[IDX_dec]) {
+ mode->c_cc[VINTR] = 3; /* ^C */
+ mode->c_cc[VERASE] = 127; /* DEL */
+ mode->c_cc[VKILL] = 21; /* ^U */
+ mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
+ if (IXANY) mode->c_iflag &= ~IXANY;
}
+}
- *bpout = '\0';
- return (const char *) buf;
+static void set_control_char_or_die(const struct control_info *info,
+ const char *arg, struct termios *mode)
+{
+ unsigned char value;
+
+ if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
+ value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
+ else if (arg[0] == '\0' || arg[1] == '\0')
+ value = arg[0];
+ else if (!strcmp(arg, "^-") || !strcmp(arg, "undef"))
+ value = _POSIX_VDISABLE;
+ else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
+ value = arg[1] & 0x1f; /* Non-letters get weird results */
+ if (arg[1] == '?')
+ value = 127;
+ } else
+ value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
+ mode->c_cc[info->offset] = value;
}
-#ifdef TEST
+#define STTY_require_set_attr (1 << 0)
+#define STTY_speed_was_set (1 << 1)
+#define STTY_verbose_output (1 << 2)
+#define STTY_recoverable_output (1 << 3)
+#define STTY_noargs (1 << 4)
+
+int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int stty_main(int argc, char **argv)
+{
+ struct termios mode;
+ void (*output_func)(const struct termios *, const int);
+ const char *file_name = NULL;
+ int display_all = 0;
+ int stty_state;
+ int k;
+
+ INIT_G();
+
+ stty_state = STTY_noargs;
+ output_func = do_display;
+
+ /* First pass: only parse/verify command line params */
+ k = 0;
+ while (argv[++k]) {
+ const struct mode_info *mp;
+ const struct control_info *cp;
+ const char *arg = argv[k];
+ const char *argnext = argv[k+1];
+ int param;
+
+ if (arg[0] == '-') {
+ int i;
+ mp = find_mode(arg+1);
+ if (mp) {
+ if (!(mp->flags & REV))
+ goto invalid_argument;
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+ /* It is an option - parse it */
+ i = 0;
+ while (arg[++i]) {
+ switch (arg[i]) {
+ case 'a':
+ stty_state |= STTY_verbose_output;
+ output_func = do_display;
+ display_all = 1;
+ break;
+ case 'g':
+ stty_state |= STTY_recoverable_output;
+ output_func = display_recoverable;
+ break;
+ case 'F':
+ if (file_name)
+ bb_error_msg_and_die("only one device may be specified");
+ file_name = &arg[i+1]; /* "-Fdevice" ? */
+ if (!file_name[0]) { /* nope, "-F device" */
+ int p = k+1; /* argv[p] is argnext */
+ file_name = argnext;
+ if (!file_name)
+ bb_error_msg_and_die(bb_msg_requires_arg, "-F");
+ /* remove -F param from arg[vc] */
+ --argc;
+ while (argv[p]) { argv[p] = argv[p+1]; ++p; }
+ }
+ goto end_option;
+ default:
+ goto invalid_argument;
+ }
+ }
+ end_option:
+ continue;
+ }
+
+ mp = find_mode(arg);
+ if (mp) {
+ stty_state &= ~STTY_noargs;
+ continue;
+ }
+
+ cp = find_control(arg);
+ if (cp) {
+ if (!argnext)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ /* called for the side effect of xfunc death only */
+ set_control_char_or_die(cp, argnext, &mode);
+ stty_state &= ~STTY_noargs;
+ ++k;
+ continue;
+ }
+
+ param = find_param(arg);
+ if (param & param_need_arg) {
+ if (!argnext)
+ bb_error_msg_and_die(bb_msg_requires_arg, arg);
+ ++k;
+ }
+
+ switch (param) {
+#ifdef HAVE_C_LINE
+ case param_line:
+# ifndef TIOCGWINSZ
+ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
+ break;
+# endif /* else fall-through */
+#endif
+#ifdef TIOCGWINSZ
+ case param_rows:
+ case param_cols:
+ case param_columns:
+ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
+ break;
+ case param_size:
+#endif
+ case param_speed:
+ break;
+ case param_ispeed:
+ /* called for the side effect of xfunc death only */
+ set_speed_or_die(input_speed, argnext, &mode);
+ break;
+ case param_ospeed:
+ /* called for the side effect of xfunc death only */
+ set_speed_or_die(output_speed, argnext, &mode);
+ break;
+ default:
+ if (recover_mode(arg, &mode) == 1) break;
+ if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
+ invalid_argument:
+ bb_error_msg_and_die("invalid argument '%s'", arg);
+ }
+ stty_state &= ~STTY_noargs;
+ }
+
+ /* Specifying both -a and -g is an error */
+ if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
+ (STTY_verbose_output | STTY_recoverable_output))
+ bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
+ /* Specifying -a or -g with non-options is an error */
+ if (!(stty_state & STTY_noargs) &&
+ (stty_state & (STTY_verbose_output | STTY_recoverable_output)))
+ bb_error_msg_and_die("modes may not be set when specifying an output style");
+
+ /* Now it is safe to start doing things */
+ if (file_name) {
+ int fd, fdflags;
+ G.device_name = file_name;
+ fd = xopen(G.device_name, O_RDONLY | O_NONBLOCK);
+ if (fd != STDIN_FILENO) {
+ dup2(fd, STDIN_FILENO);
+ close(fd);
+ }
+ fdflags = fcntl(STDIN_FILENO, F_GETFL);
+ if (fdflags < 0 ||
+ fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+ perror_on_device_and_die("%s: cannot reset non-blocking mode");
+ }
+
+ /* Initialize to all zeroes so there is no risk memcmp will report a
+ spurious difference in an uninitialized portion of the structure */
+ memset(&mode, 0, sizeof(mode));
+ if (tcgetattr(STDIN_FILENO, &mode))
+ perror_on_device_and_die("%s");
+
+ if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
+ get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
+ output_func(&mode, display_all);
+ return EXIT_SUCCESS;
+ }
+
+ /* Second pass: perform actions */
+ k = 0;
+ while (argv[++k]) {
+ const struct mode_info *mp;
+ const struct control_info *cp;
+ const char *arg = argv[k];
+ const char *argnext = argv[k+1];
+ int param;
+
+ if (arg[0] == '-') {
+ mp = find_mode(arg+1);
+ if (mp) {
+ set_mode(mp, 1 /* reversed */, &mode);
+ stty_state |= STTY_require_set_attr;
+ }
+ /* It is an option - already parsed. Skip it */
+ continue;
+ }
+
+ mp = find_mode(arg);
+ if (mp) {
+ set_mode(mp, 0 /* non-reversed */, &mode);
+ stty_state |= STTY_require_set_attr;
+ continue;
+ }
+
+ cp = find_control(arg);
+ if (cp) {
+ ++k;
+ set_control_char_or_die(cp, argnext, &mode);
+ stty_state |= STTY_require_set_attr;
+ continue;
+ }
+
+ param = find_param(arg);
+ if (param & param_need_arg) {
+ ++k;
+ }
+
+ switch (param) {
+#ifdef HAVE_C_LINE
+ case param_line:
+ mode.c_line = xatoul_sfx(argnext, stty_suffixes);
+ stty_state |= STTY_require_set_attr;
+ break;
+#endif
+#ifdef TIOCGWINSZ
+ case param_cols:
+ set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
+ break;
+ case param_size:
+ display_window_size(0);
+ break;
+ case param_rows:
+ set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
+ break;
+#endif
+ case param_speed:
+ display_speed(&mode, 0);
+ break;
+ case param_ispeed:
+ set_speed_or_die(input_speed, argnext, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ break;
+ case param_ospeed:
+ set_speed_or_die(output_speed, argnext, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ break;
+ default:
+ if (recover_mode(arg, &mode) == 1)
+ stty_state |= STTY_require_set_attr;
+ else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
+ set_speed_or_die(both_speeds, arg, &mode);
+ stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
+ } /* else - impossible (caught in the first pass):
+ bb_error_msg_and_die("invalid argument '%s'", arg); */
+ }
+ }
+
+ if (stty_state & STTY_require_set_attr) {
+ struct termios new_mode;
-const char *bb_applet_name = "stty";
+ if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
+ perror_on_device_and_die("%s");
+ /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
+ it performs *any* of the requested operations. This means it
+ can report 'success' when it has actually failed to perform
+ some proper subset of the requested operations. To detect
+ this partial failure, get the current terminal attributes and
+ compare them to the requested ones */
+
+ /* Initialize to all zeroes so there is no risk memcmp will report a
+ spurious difference in an uninitialized portion of the structure */
+ memset(&new_mode, 0, sizeof(new_mode));
+ if (tcgetattr(STDIN_FILENO, &new_mode))
+ perror_on_device_and_die("%s");
+
+ if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
+#ifdef CIBAUD
+ /* SunOS 4.1.3 (at least) has the problem that after this sequence,
+ tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
+ sometimes (m1 != m2). The only difference is in the four bits
+ of the c_cflag field corresponding to the baud rate. To save
+ Sun users a little confusion, don't report an error if this
+ happens. But suppress the error only if we haven't tried to
+ set the baud rate explicitly -- otherwise we'd never give an
+ error for a true failure to set the baud rate */
+
+ new_mode.c_cflag &= (~CIBAUD);
+ if ((stty_state & STTY_speed_was_set)
+ || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
#endif
+ perror_on_device_and_die("%s: cannot perform all requested operations");
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/coreutils/sum.c b/release/src/router/busybox/coreutils/sum.c
new file mode 100644
index 00000000..60f3b300
--- /dev/null
+++ b/release/src/router/busybox/coreutils/sum.c
@@ -0,0 +1,99 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * sum -- checksum and count the blocks in a file
+ * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given.
+ *
+ * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
+ *
+ * Written by Kayvan Aghaiepour and David MacKenzie
+ * Taken from coreutils and turned into a busybox applet by Mike Frysinger
+ *
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ */
+
+#include "libbb.h"
+
+enum { SUM_BSD, PRINT_NAME, SUM_SYSV };
+
+/* BSD: calculate and print the rotated checksum and the size in 1K blocks
+ The checksum varies depending on sizeof (int). */
+/* SYSV: calculate and print the checksum and the size in 512-byte blocks */
+/* Return 1 if successful. */
+static unsigned sum_file(const char *file, unsigned type)
+{
+#define buf bb_common_bufsiz1
+ unsigned long long total_bytes = 0;
+ int fd, r;
+ /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
+ unsigned s = 0;
+
+ fd = open_or_warn_stdin(file);
+ if (fd == -1)
+ return 0;
+
+ while (1) {
+ size_t bytes_read = safe_read(fd, buf, BUFSIZ);
+
+ if ((ssize_t)bytes_read <= 0) {
+ r = (fd && close(fd) != 0);
+ if (!bytes_read && !r)
+ /* no error */
+ break;
+ bb_perror_msg(file);
+ return 0;
+ }
+
+ total_bytes += bytes_read;
+ if (type >= SUM_SYSV) {
+ do s += buf[--bytes_read]; while (bytes_read);
+ } else {
+ r = 0;
+ do {
+ s = (s >> 1) + ((s & 1) << 15);
+ s += buf[r++];
+ s &= 0xffff; /* Keep it within bounds. */
+ } while (--bytes_read);
+ }
+ }
+
+ if (type < PRINT_NAME)
+ file = "";
+ if (type >= SUM_SYSV) {
+ r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
+ s = (r & 0xffff) + (r >> 16);
+ printf("%d %llu %s\n", s, (total_bytes + 511) / 512, file);
+ } else
+ printf("%05d %5llu %s\n", s, (total_bytes + 1023) / 1024, file);
+ return 1;
+#undef buf
+}
+
+int sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sum_main(int argc UNUSED_PARAM, char **argv)
+{
+ unsigned n;
+ unsigned type = SUM_BSD;
+
+ n = getopt32(argv, "sr");
+ argv += optind;
+ if (n & 1) type = SUM_SYSV;
+ /* give the bsd priority over sysv func */
+ if (n & 2) type = SUM_BSD;
+
+ if (!argv[0]) {
+ /* Do not print the name */
+ n = sum_file("-", type);
+ } else {
+ /* Need to print the name if either
+ - more than one file given
+ - doing sysv */
+ type += (argv[1] || type == SUM_SYSV);
+ n = 1;
+ do {
+ n &= sum_file(*argv, type);
+ } while (*++argv);
+ }
+ return !n;
+}
diff --git a/release/src/router/busybox/coreutils/sync.c b/release/src/router/busybox/coreutils/sync.c
index 84746311..f00a3d07 100644
--- a/release/src/router/busybox/coreutils/sync.c
+++ b/release/src/router/busybox/coreutils/sync.c
@@ -4,33 +4,22 @@
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int sync_main(int argc, char **argv)
+int sync_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int sync_main(int argc, char **argv UNUSED_PARAM)
{
+ /* coreutils-6.9 compat */
bb_warn_ignoring_args(argc - 1);
sync();
- return(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/coreutils/tac.c b/release/src/router/busybox/coreutils/tac.c
new file mode 100644
index 00000000..d70e23ad
--- /dev/null
+++ b/release/src/router/busybox/coreutils/tac.c
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * tac implementation for busybox
+ *
+ * Copyright (C) 2003 Yang Xiaopeng <yxp at hanwang.com.cn>
+ * Copyright (C) 2007 Natanael Copa <natanael.copa@gmail.com>
+ * Copyright (C) 2007 Tito Ragusa <farmatito@tiscali.it>
+ *
+ * Licensed under GPLv2, see file License in this tarball for details.
+ *
+ */
+
+/* tac - concatenate and print files in reverse */
+
+/* Based on Yang Xiaopeng's (yxp at hanwang.com.cn) patch
+ * http://www.uclibc.org/lists/busybox/2003-July/008813.html
+ */
+
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
+struct lstring {
+ int size;
+ char buf[1];
+};
+
+int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tac_main(int argc UNUSED_PARAM, char **argv)
+{
+ char **name;
+ FILE *f;
+ struct lstring *line = NULL;
+ llist_t *list = NULL;
+ int retval = EXIT_SUCCESS;
+
+#if ENABLE_DESKTOP
+/* tac from coreutils 6.9 supports:
+ -b, --before
+ attach the separator before instead of after
+ -r, --regex
+ interpret the separator as a regular expression
+ -s, --separator=STRING
+ use STRING as the separator instead of newline
+We support none, but at least we will complain or handle "--":
+*/
+ getopt32(argv, "");
+ argv += optind;
+#else
+ argv++;
+#endif
+ if (!*argv)
+ *--argv = (char *)"-";
+ /* We will read from last file to first */
+ name = argv;
+ while (*name)
+ name++;
+
+ do {
+ int ch, i;
+
+ name--;
+ f = fopen_or_warn_stdin(*name);
+ if (f == NULL) {
+ /* error message is printed by fopen_or_warn_stdin */
+ retval = EXIT_FAILURE;
+ continue;
+ }
+
+ errno = i = 0;
+ do {
+ ch = fgetc(f);
+ if (ch != EOF) {
+ if (!(i & 0x7f))
+ /* Grow on every 128th char */
+ line = xrealloc(line, i + 0x7f + sizeof(int) + 1);
+ line->buf[i++] = ch;
+ }
+ if (ch == '\n' || (ch == EOF && i != 0)) {
+ line = xrealloc(line, i + sizeof(int));
+ line->size = i;
+ llist_add_to(&list, line);
+ line = NULL;
+ i = 0;
+ }
+ } while (ch != EOF);
+ /* fgetc sets errno to ENOENT on EOF, we don't want
+ * to warn on this non-error! */
+ if (errno && errno != ENOENT) {
+ bb_simple_perror_msg(*name);
+ retval = EXIT_FAILURE;
+ }
+ } while (name != argv);
+
+ while (list) {
+ line = (struct lstring *)list->data;
+ xwrite(STDOUT_FILENO, line->buf, line->size);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(llist_pop(&list));
+ } else {
+ list = list->link;
+ }
+ }
+
+ return retval;
+}
diff --git a/release/src/router/busybox/coreutils/tail.c b/release/src/router/busybox/coreutils/tail.c
index 10b5cd7a..5dae2d35 100644
--- a/release/src/router/busybox/coreutils/tail.c
+++ b/release/src/router/busybox/coreutils/tail.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant (need fancy for -c) */
@@ -37,303 +24,261 @@
* 7) lseek attempted when count==0 even if arg was +0 (from top)
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include "busybox.h"
+#include "libbb.h"
static const struct suffix_mult tail_suffixes[] = {
{ "b", 512 },
{ "k", 1024 },
- { "m", 1048576 },
- { NULL, 0 }
+ { "m", 1024*1024 },
+ { }
};
-static int status
-#if EXIT_SUCCESS != 0
- = EXIT_SUCCESS /* If it is 0 (paranoid check), let bss initialize it. */
-#endif
- ;
+struct globals {
+ bool status;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
static void tail_xprint_header(const char *fmt, const char *filename)
{
- /* If we get an output error, there is really no sense in continuing. */
- if (dprintf(STDOUT_FILENO, fmt, filename) < 0) {
- bb_perror_nomsg_and_die();
- }
-}
-
-/* len should probably be size_t */
-static void tail_xbb_full_write(const char *buf, size_t len)
-{
- /* If we get a write error, there is really no sense in continuing. */
- if (bb_full_write(STDOUT_FILENO, buf, len) < 0) {
+ if (fdprintf(STDOUT_FILENO, fmt, filename) < 0)
bb_perror_nomsg_and_die();
- }
}
static ssize_t tail_read(int fd, char *buf, size_t count)
{
ssize_t r;
-
- if ((r = safe_read(fd, buf, count)) < 0) {
- bb_perror_msg("read");
- status = EXIT_FAILURE;
+ off_t current;
+ struct stat sbuf;
+
+ /* (A good comment is missing here) */
+ current = lseek(fd, 0, SEEK_CUR);
+ /* /proc files report zero st_size, don't lseek them. */
+ if (fstat(fd, &sbuf) == 0 && sbuf.st_size)
+ if (sbuf.st_size < current)
+ lseek(fd, 0, SEEK_SET);
+
+ r = full_read(fd, buf, count);
+ if (r < 0) {
+ bb_perror_msg(bb_msg_read_error);
+ G.status = EXIT_FAILURE;
}
return r;
}
-static const char tail_opts[] =
- "fn:"
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- "c:qs:v"
-#endif
- ;
+static const char header_fmt[] ALIGN1 = "\n==> %s <==\n";
-static const char header_fmt[] = "\n==> %s <==\n";
+static unsigned eat_num(const char *p)
+{
+ if (*p == '-')
+ p++;
+ else if (*p == '+') {
+ p++;
+ G.status = 1; /* mark that we saw "+" */
+ }
+ return xatou_sfx(p, tail_suffixes);
+}
+int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int tail_main(int argc, char **argv)
{
- long count = 10;
- unsigned int sleep_period = 1;
- int from_top = 0;
- int follow = 0;
+ unsigned count = 10;
+ unsigned sleep_period = 1;
+ bool from_top;
int header_threshhold = 1;
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- int count_bytes = 0;
-#endif
+ const char *str_c, *str_n;
char *tailbuf;
size_t tailbufsize;
int taillen = 0;
- int newline = 0;
+ int newlines_seen = 0;
+ int nfiles, nread, nwrite, i, opt;
+ unsigned seen;
- int *fds, nfiles, nread, nwrite, seen, i, opt;
+ int *fds;
char *s, *buf;
const char *fmt;
+#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
/* Allow legacy syntax of an initial numeric option without -n. */
- if (argc >=2 && ((argv[1][0] == '+') || ((argv[1][0] == '-')
- /* && (isdigit)(argv[1][1]) */
- && (((unsigned int)(argv[1][1] - '0')) <= 9))))
- {
- optind = 2;
- optarg = argv[1];
- goto GET_COUNT;
+ if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-')
+ && isdigit(argv[1][1])
+ ) {
+ count = eat_num(argv[1]);
+ argv++;
+ argc--;
}
-
- while ((opt = getopt(argc, argv, tail_opts)) > 0) {
- switch (opt) {
- case 'f':
- follow = 1;
- break;
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- case 'c':
- count_bytes = 1;
- /* FALLS THROUGH */
-#endif
- case 'n':
- GET_COUNT:
- count = bb_xgetlarg10_sfx(optarg, tail_suffixes);
- /* Note: Leading whitespace is an error trapped above. */
- if (*optarg == '+') {
- from_top = 1;
- } else {
- from_top = 0;
- }
- if (count < 0) {
- count = -count;
- }
- break;
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- case 'q':
- header_threshhold = INT_MAX;
- break;
- case 's':
- sleep_period =bb_xgetularg10_bnd(optarg, 0, UINT_MAX);
- break;
- case 'v':
- header_threshhold = 0;
- break;
#endif
- default:
- bb_show_usage();
- }
- }
-
- /* open all the files */
- fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1));
+ USE_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
+ opt = getopt32(argv, "fc:n:" USE_FEATURE_FANCY_TAIL("qs:v"),
+ &str_c, &str_n USE_FEATURE_FANCY_TAIL(,&sleep_period));
+#define FOLLOW (opt & 0x1)
+#define COUNT_BYTES (opt & 0x2)
+ //if (opt & 0x1) // -f
+ if (opt & 0x2) count = eat_num(str_c); // -c
+ if (opt & 0x4) count = eat_num(str_n); // -n
+#if ENABLE_FEATURE_FANCY_TAIL
+ if (opt & 0x8) header_threshhold = INT_MAX; // -q
+ if (opt & 0x20) header_threshhold = 0; // -v
+#endif
+ argc -= optind;
argv += optind;
- nfiles = i = 0;
+ from_top = G.status; /* 1 if there was "-c +N" or "-n +N" */
+ G.status = EXIT_SUCCESS;
- if ((argc -= optind) == 0) {
+ /* open all the files */
+ fds = xmalloc(sizeof(int) * (argc + 1));
+ if (!argv[0]) {
struct stat statbuf;
if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) {
- follow = 0;
+ opt &= ~1; /* clear FOLLOW */
}
- /* --argv; */
*argv = (char *) bb_msg_standard_input;
- goto DO_STDIN;
}
-
+ nfiles = i = 0;
do {
- if ((argv[i][0] == '-') && !argv[i][1]) {
- DO_STDIN:
- fds[nfiles] = STDIN_FILENO;
- } else if ((fds[nfiles] = open(argv[i], O_RDONLY)) < 0) {
- bb_perror_msg("%s", argv[i]);
- status = EXIT_FAILURE;
+ int fd = open_or_warn_stdin(argv[i]);
+ if (fd < 0) {
+ G.status = EXIT_FAILURE;
continue;
}
- argv[nfiles] = argv[i];
- ++nfiles;
+ fds[nfiles] = fd;
+ argv[nfiles++] = argv[i];
} while (++i < argc);
- if (!nfiles) {
+ if (!nfiles)
bb_error_msg_and_die("no files");
- }
+ /* prepare the buffer */
tailbufsize = BUFSIZ;
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- /* tail the files */
- if (from_top < count_bytes) { /* Each is 0 or 1, so true iff 0 < 1. */
- /* Hence, !from_top && count_bytes */
- if (tailbufsize < count) {
+ if (!from_top && COUNT_BYTES) {
+ if (tailbufsize < count + BUFSIZ) {
tailbufsize = count + BUFSIZ;
}
}
-#endif
- buf = tailbuf = xmalloc(tailbufsize);
+ tailbuf = xmalloc(tailbufsize);
+ /* tail the files */
fmt = header_fmt + 1; /* Skip header leading newline on first output. */
i = 0;
do {
- /* Be careful. It would be possible to optimize the count-bytes
- * case if the file is seekable. If you do though, remember that
- * starting file position may not be the beginning of the file.
- * Beware of backing up too far. See example in wc.c.
- */
- if ((!(count|from_top)) && (lseek(fds[i], 0, SEEK_END) >= 0)) {
- continue;
- }
-
if (nfiles > header_threshhold) {
tail_xprint_header(fmt, argv[i]);
fmt = header_fmt;
}
+ /* Optimizing count-bytes case if the file is seekable.
+ * Beware of backing up too far.
+ * Also we exclude files with size 0 (because of /proc/xxx) */
+ if (COUNT_BYTES && !from_top) {
+ off_t current = lseek(fds[i], 0, SEEK_END);
+ if (current > 0) {
+ if (count == 0)
+ continue; /* showing zero lines is easy :) */
+ current -= count;
+ if (current < 0)
+ current = 0;
+ xlseek(fds[i], current, SEEK_SET);
+ bb_copyfd_size(fds[i], STDOUT_FILENO, count);
+ continue;
+ }
+ }
+
buf = tailbuf;
taillen = 0;
seen = 1;
-
+ newlines_seen = 0;
while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
if (from_top) {
nwrite = nread;
if (seen < count) {
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- if (count_bytes) {
+ if (COUNT_BYTES) {
nwrite -= (count - seen);
seen = count;
- } else
-#endif
- {
+ } else {
s = buf;
do {
--nwrite;
- if ((*s++ == '\n') && (++seen == count)) {
+ if (*s++ == '\n' && ++seen == count) {
break;
}
} while (nwrite);
}
}
- tail_xbb_full_write(buf + nread - nwrite, nwrite);
+ xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
} else if (count) {
-#ifdef CONFIG_FEATURE_FANCY_TAIL
- if (count_bytes) {
+ if (COUNT_BYTES) {
taillen += nread;
- if (taillen > count) {
+ if (taillen > (int)count) {
memmove(tailbuf, tailbuf + taillen - count, count);
taillen = count;
}
- } else
-#endif
- {
+ } else {
int k = nread;
- int nbuf = 0;
+ int newlines_in_buf = 0;
- while (k) {
- --k;
+ do { /* count '\n' in last read */
+ k--;
if (buf[k] == '\n') {
- ++nbuf;
+ newlines_in_buf++;
}
- }
+ } while (k);
- if (newline + nbuf < count) {
- newline += nbuf;
+ if (newlines_seen + newlines_in_buf < (int)count) {
+ newlines_seen += newlines_in_buf;
taillen += nread;
-
} else {
- int extra = 0;
- if (buf[nread-1] != '\n') {
- extra = 1;
- }
+ int extra = (buf[nread-1] != '\n');
- k = newline + nbuf + extra - count;
+ k = newlines_seen + newlines_in_buf + extra - count;
s = tailbuf;
while (k) {
if (*s == '\n') {
- --k;
+ k--;
}
- ++s;
+ s++;
}
-
taillen += nread - (s - tailbuf);
memmove(tailbuf, s, taillen);
- newline = count - extra;
+ newlines_seen = count - extra;
}
- if (tailbufsize < taillen + BUFSIZ) {
+ if (tailbufsize < (size_t)taillen + BUFSIZ) {
tailbufsize = taillen + BUFSIZ;
tailbuf = xrealloc(tailbuf, tailbufsize);
}
}
buf = tailbuf + taillen;
}
- }
-
+ } /* while (tail_read() > 0) */
if (!from_top) {
- tail_xbb_full_write(tailbuf, taillen);
+ xwrite(STDOUT_FILENO, tailbuf, taillen);
}
-
- taillen = 0;
} while (++i < nfiles);
buf = xrealloc(tailbuf, BUFSIZ);
fmt = NULL;
- while (follow) {
+ if (FOLLOW) while (1) {
sleep(sleep_period);
i = 0;
do {
if (nfiles > header_threshhold) {
fmt = header_fmt;
}
- while ((nread = tail_read(fds[i], buf, sizeof(buf))) > 0) {
+ while ((nread = tail_read(fds[i], buf, BUFSIZ)) > 0) {
if (fmt) {
tail_xprint_header(fmt, argv[i]);
fmt = NULL;
}
- tail_xbb_full_write(buf, nread);
+ xwrite(STDOUT_FILENO, buf, nread);
}
} while (++i < nfiles);
}
-
- return status;
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(fds);
+ }
+ return G.status;
}
diff --git a/release/src/router/busybox/coreutils/tee.c b/release/src/router/busybox/coreutils/tee.c
index 7e86f2e2..0f242467 100644
--- a/release/src/router/busybox/coreutils/tee.c
+++ b/release/src/router/busybox/coreutils/tee.c
@@ -4,112 +4,103 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int tee_main(int argc, char **argv)
{
const char *mode = "w\0a";
FILE **files;
- FILE **p;
- char **filenames;
- int flags;
- int retval = EXIT_SUCCESS;
-#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
- size_t c;
- RESERVE_CONFIG_BUFFER(buf, BUFSIZ);
+ FILE **fp;
+ char **names;
+ char **np;
+ char retval;
+//TODO: make unconditional
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+ ssize_t c;
+# define buf bb_common_bufsiz1
#else
int c;
#endif
+ retval = getopt32(argv, "ia"); /* 'a' must be 2nd */
+ argc -= optind;
+ argv += optind;
- flags = bb_getopt_ulflags(argc, argv, "ia"); /* 'a' must be 2nd */
-
- mode += (flags & 2); /* Since 'a' is the 2nd option... */
+ mode += (retval & 2); /* Since 'a' is the 2nd option... */
- if (flags & 1) {
- signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction.*/
+ if (retval & 1) {
+ signal(SIGINT, SIG_IGN); /* TODO - switch to sigaction. (why?) */
}
-
+ retval = EXIT_SUCCESS;
/* gnu tee ignores SIGPIPE in case one of the output files is a pipe
* that doesn't consume all its input. Good idea... */
- signal(SIGPIPE, SIG_IGN); /* TODO - switch to sigaction.*/
+ signal(SIGPIPE, SIG_IGN);
/* Allocate an array of FILE *'s, with one extra for a sentinal. */
- p = files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 2));
- *p = stdout;
- argv += optind - 1;
- filenames = argv - 1;
- *filenames = (char *) bb_msg_standard_input; /* for later */
- goto GOT_NEW_FILE;
+ fp = files = xzalloc(sizeof(FILE *) * (argc + 2));
+ np = names = argv - 1;
+ files[0] = stdout;
+ goto GOT_NEW_FILE;
do {
- if ((*p = bb_wfopen(*argv, mode)) == NULL) {
- retval = EXIT_FAILURE;
- continue;
- }
- filenames[(int)(p - files)] = *argv;
- GOT_NEW_FILE:
- setbuf(*p, NULL); /* tee must not buffer output. */
- ++p;
- } while (*++argv);
-
- *p = NULL; /* Store the sentinal value. */
-
-#ifdef CONFIG_FEATURE_TEE_USE_BLOCK_IO
- while ((c = fread(buf, 1, BUFSIZ, stdin)) != 0) {
- for (p=files ; *p ; p++) {
- fwrite(buf, 1, c, *p);
+ *fp = stdout;
+ if (NOT_LONE_DASH(*argv)) {
+ *fp = fopen_or_warn(*argv, mode);
+ if (*fp == NULL) {
+ retval = EXIT_FAILURE;
+ argv++;
+ continue;
+ }
}
+ *np = *argv++;
+ GOT_NEW_FILE:
+ setbuf(*fp, NULL); /* tee must not buffer output. */
+ fp++;
+ np++;
+ } while (*argv);
+ /* names[0] will be filled later */
+
+#if ENABLE_FEATURE_TEE_USE_BLOCK_IO
+ while ((c = safe_read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ fp = files;
+ do
+ fwrite(buf, 1, c, *fp++);
+ while (*fp);
+ }
+ if (c < 0) { /* Make sure read errors are signaled. */
+ retval = EXIT_FAILURE;
}
-
-#ifdef CONFIG_FEATURE_CLEAN_UP
- RELEASE_CONFIG_BUFFER(buf);
-#endif
-
#else
+ setvbuf(stdout, NULL, _IONBF, 0);
while ((c = getchar()) != EOF) {
- for (p=files ; *p ; p++) {
- putc(c, *p);
- }
+ fp = files;
+ do
+ putc(c, *fp++);
+ while (*fp);
}
#endif
- /* Now we need to check for i/o errors on stdin and the various
+ /* Now we need to check for i/o errors on stdin and the various
* output files. Since we know that the first entry in the output
* file table is stdout, we can save one "if ferror" test by
* setting the first entry to stdin and checking stdout error
- * status with bb_fflush_stdout_and_exit()... although fflush()ing
+ * status with fflush_stdout_and_exit()... although fflush()ing
* is unnecessary here. */
-
- p = files;
- *p = stdin;
- do { /* Now check for (input and) output errors. */
+ np = names;
+ fp = files;
+ names[0] = (char *) bb_msg_standard_input;
+ files[0] = stdin;
+ do { /* Now check for input and output errors. */
/* Checking ferror should be sufficient, but we may want to fclose.
* If we do, remember not to close stdin! */
- bb_xferror(*p, filenames[(int)(p - files)]);
- } while (*++p);
+ die_if_ferror(*fp++, *np++);
+ } while (*fp);
- bb_fflush_stdout_and_exit(retval);
+ fflush_stdout_and_exit(retval);
}
diff --git a/release/src/router/busybox/coreutils/test.c b/release/src/router/busybox/coreutils/test.c
index 2ad326ea..ab7b4168 100644
--- a/release/src/router/busybox/coreutils/test.c
+++ b/release/src/router/busybox/coreutils/test.c
@@ -2,48 +2,39 @@
/*
* test implementation for busybox
*
- * Copyright (c) by a whole pile of folks:
+ * Copyright (c) by a whole pile of folks:
*
- * test(1); version 7-like -- author Erik Baalbergen
- * modified by Eric Gisin to be used as built-in.
- * modified by Arnold Robbins to add SVR3 compatibility
- * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
- * modified by J.T. Conklin for NetBSD.
- * modified by Herbert Xu to be used as built-in in ash.
- * modified by Erik Andersen <andersen@codepoet.org> to be used
- * in busybox.
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ * modified by Herbert Xu to be used as built-in in ash.
+ * modified by Erik Andersen <andersen@codepoet.org> to be used
+ * in busybox.
+ * modified by Bernhard Reutner-Fischer to be useable (i.e. a bit less bloaty).
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
* Original copyright notice states:
- * "This program is in the Public Domain."
+ * "This program is in the Public Domain."
*/
-#include <sys/types.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "busybox.h"
+#include "libbb.h"
+#include <setjmp.h>
+
+/* This is a NOFORK applet. Be very careful! */
+
+/* test_main() is called from shells, and we need to be extra careful here.
+ * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL
+ * state. */
+
/* test(1) accepts the following grammar:
oexpr ::= aexpr | aexpr "-o" oexpr ;
aexpr ::= nexpr | nexpr "-a" aexpr ;
nexpr ::= primary | "!" primary
- primary ::= unary-operator operand
+ primary ::= unary-operator operand
| operand binary-operator operand
| operand
| "(" oexpr ")"
@@ -51,11 +42,13 @@
unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
- binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
"-nt"|"-ot"|"-ef";
operand ::= <any legal UNIX file name>
*/
+#define TEST_DEBUG 0
+
enum token {
EOI,
FILRD,
@@ -98,6 +91,84 @@ enum token {
RPAREN,
OPERAND
};
+#define is_int_op(a) (((unsigned char)((a) - INTEQ)) <= 5)
+#define is_str_op(a) (((unsigned char)((a) - STREZ)) <= 5)
+#define is_file_op(a) (((unsigned char)((a) - FILNT)) <= 2)
+#define is_file_access(a) (((unsigned char)((a) - FILRD)) <= 2)
+#define is_file_type(a) (((unsigned char)((a) - FILREG)) <= 5)
+#define is_file_bit(a) (((unsigned char)((a) - FILSUID)) <= 2)
+
+#if TEST_DEBUG
+int depth;
+#define nest_msg(...) do { \
+ depth++; \
+ fprintf(stderr, "%*s", depth*2, ""); \
+ fprintf(stderr, __VA_ARGS__); \
+} while (0)
+#define unnest_msg(...) do { \
+ fprintf(stderr, "%*s", depth*2, ""); \
+ fprintf(stderr, __VA_ARGS__); \
+ depth--; \
+} while (0)
+#define dbg_msg(...) do { \
+ fprintf(stderr, "%*s", depth*2, ""); \
+ fprintf(stderr, __VA_ARGS__); \
+} while (0)
+#define unnest_msg_and_return(expr, ...) do { \
+ number_t __res = (expr); \
+ fprintf(stderr, "%*s", depth*2, ""); \
+ fprintf(stderr, __VA_ARGS__, res); \
+ depth--; \
+ return __res; \
+} while (0)
+static const char *const TOKSTR[] = {
+ "EOI",
+ "FILRD",
+ "FILWR",
+ "FILEX",
+ "FILEXIST",
+ "FILREG",
+ "FILDIR",
+ "FILCDEV",
+ "FILBDEV",
+ "FILFIFO",
+ "FILSOCK",
+ "FILSYM",
+ "FILGZ",
+ "FILTT",
+ "FILSUID",
+ "FILSGID",
+ "FILSTCK",
+ "FILNT",
+ "FILOT",
+ "FILEQ",
+ "FILUID",
+ "FILGID",
+ "STREZ",
+ "STRNZ",
+ "STREQ",
+ "STRNE",
+ "STRLT",
+ "STRGT",
+ "INTEQ",
+ "INTNE",
+ "INTGE",
+ "INTGT",
+ "INTLE",
+ "INTLT",
+ "UNOT",
+ "BAND",
+ "BOR",
+ "LPAREN",
+ "RPAREN",
+ "OPERAND"
+};
+#else
+#define nest_msg(...) ((void)0)
+#define unnest_msg(...) ((void)0)
+#define dbg_msg(...) ((void)0)
+#define unnest_msg_and_return(expr, ...) return expr
+#endif
enum token_types {
UNOP,
@@ -107,245 +178,324 @@ enum token_types {
PAREN
};
-static const struct t_op {
- const char *op_text;
- short op_num, op_type;
-} ops[] = {
- {
- "-r", FILRD, UNOP}, {
- "-w", FILWR, UNOP}, {
- "-x", FILEX, UNOP}, {
- "-e", FILEXIST, UNOP}, {
- "-f", FILREG, UNOP}, {
- "-d", FILDIR, UNOP}, {
- "-c", FILCDEV, UNOP}, {
- "-b", FILBDEV, UNOP}, {
- "-p", FILFIFO, UNOP}, {
- "-u", FILSUID, UNOP}, {
- "-g", FILSGID, UNOP}, {
- "-k", FILSTCK, UNOP}, {
- "-s", FILGZ, UNOP}, {
- "-t", FILTT, UNOP}, {
- "-z", STREZ, UNOP}, {
- "-n", STRNZ, UNOP}, {
- "-h", FILSYM, UNOP}, /* for backwards compat */
- {
- "-O", FILUID, UNOP}, {
- "-G", FILGID, UNOP}, {
- "-L", FILSYM, UNOP}, {
- "-S", FILSOCK, UNOP}, {
- "=", STREQ, BINOP}, {
- "!=", STRNE, BINOP}, {
- "<", STRLT, BINOP}, {
- ">", STRGT, BINOP}, {
- "-eq", INTEQ, BINOP}, {
- "-ne", INTNE, BINOP}, {
- "-ge", INTGE, BINOP}, {
- "-gt", INTGT, BINOP}, {
- "-le", INTLE, BINOP}, {
- "-lt", INTLT, BINOP}, {
- "-nt", FILNT, BINOP}, {
- "-ot", FILOT, BINOP}, {
- "-ef", FILEQ, BINOP}, {
- "!", UNOT, BUNOP}, {
- "-a", BAND, BBINOP}, {
- "-o", BOR, BBINOP}, {
- "(", LPAREN, PAREN}, {
- ")", RPAREN, PAREN}, {
- 0, 0, 0}
+struct operator_t {
+ char op_text[4];
+ unsigned char op_num, op_type;
};
-static char **t_wp;
-static struct t_op const *t_wp_op;
-static gid_t *group_array = NULL;
-static int ngroups;
-
-static enum token t_lex(char *s);
-static int oexpr(enum token n);
-static int aexpr(enum token n);
-static int nexpr(enum token n);
-static int binop(void);
-static int primary(enum token n);
-static int filstat(char *nm, enum token mode);
-static int getn(const char *s);
-static int newerf(const char *f1, const char *f2);
-static int olderf(const char *f1, const char *f2);
-static int equalf(const char *f1, const char *f2);
-static void syntax(const char *op, const char *msg);
-static int test_eaccess(char *path, int mode);
-static int is_a_group_member(gid_t gid);
-static void initialize_group_array(void);
-
-extern int test_main(int argc, char **argv)
-{
- int res;
+static const struct operator_t ops[] = {
+ { "-r", FILRD , UNOP },
+ { "-w", FILWR , UNOP },
+ { "-x", FILEX , UNOP },
+ { "-e", FILEXIST, UNOP },
+ { "-f", FILREG , UNOP },
+ { "-d", FILDIR , UNOP },
+ { "-c", FILCDEV , UNOP },
+ { "-b", FILBDEV , UNOP },
+ { "-p", FILFIFO , UNOP },
+ { "-u", FILSUID , UNOP },
+ { "-g", FILSGID , UNOP },
+ { "-k", FILSTCK , UNOP },
+ { "-s", FILGZ , UNOP },
+ { "-t", FILTT , UNOP },
+ { "-z", STREZ , UNOP },
+ { "-n", STRNZ , UNOP },
+ { "-h", FILSYM , UNOP }, /* for backwards compat */
+
+ { "-O" , FILUID , UNOP },
+ { "-G" , FILGID , UNOP },
+ { "-L" , FILSYM , UNOP },
+ { "-S" , FILSOCK, UNOP },
+ { "=" , STREQ , BINOP },
+ { "==" , STREQ , BINOP },
+ { "!=" , STRNE , BINOP },
+ { "<" , STRLT , BINOP },
+ { ">" , STRGT , BINOP },
+ { "-eq", INTEQ , BINOP },
+ { "-ne", INTNE , BINOP },
+ { "-ge", INTGE , BINOP },
+ { "-gt", INTGT , BINOP },
+ { "-le", INTLE , BINOP },
+ { "-lt", INTLT , BINOP },
+ { "-nt", FILNT , BINOP },
+ { "-ot", FILOT , BINOP },
+ { "-ef", FILEQ , BINOP },
+ { "!" , UNOT , BUNOP },
+ { "-a" , BAND , BBINOP },
+ { "-o" , BOR , BBINOP },
+ { "(" , LPAREN , PAREN },
+ { ")" , RPAREN , PAREN },
+};
+
+
+#if ENABLE_FEATURE_TEST_64
+typedef int64_t number_t;
+#else
+typedef int number_t;
+#endif
- if (strcmp(bb_applet_name, "[") == 0) {
- if (strcmp(argv[--argc], "]"))
- bb_error_msg_and_die("missing ]");
- argv[argc] = NULL;
- }
- /* Implement special cases from POSIX.2, section 4.62.4 */
- switch (argc) {
- case 1:
- exit(1);
- case 2:
- exit(*argv[1] == '\0');
- case 3:
- if (argv[1][0] == '!' && argv[1][1] == '\0') {
- exit(!(*argv[2] == '\0'));
- }
- break;
- case 4:
- if (argv[1][0] != '!' || argv[1][1] != '\0') {
- if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) {
- t_wp = &argv[1];
- exit(binop() == 0);
- }
- }
- break;
- case 5:
- if (argv[1][0] == '!' && argv[1][1] == '\0') {
- if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) {
- t_wp = &argv[2];
- exit(!(binop() == 0));
- }
- }
- break;
- }
- t_wp = &argv[1];
- res = !oexpr(t_lex(*t_wp));
+/* We try to minimize both static and stack usage. */
+struct test_statics {
+ char **args;
+ /* set only by check_operator(), either to bogus struct
+ * or points to matching operator_t struct. Never NULL. */
+ const struct operator_t *last_operator;
+ gid_t *group_array;
+ int ngroups;
+ jmp_buf leaving;
+};
- if (*t_wp != NULL && *++t_wp != NULL)
- syntax(*t_wp, "unknown operand");
+/* See test_ptr_hack.c */
+extern struct test_statics *const test_ptr_to_statics;
- return (res);
-}
+#define S (*test_ptr_to_statics)
+#define args (S.args )
+#define last_operator (S.last_operator)
+#define group_array (S.group_array )
+#define ngroups (S.ngroups )
+#define leaving (S.leaving )
+#define INIT_S() do { \
+ (*(struct test_statics**)&test_ptr_to_statics) = xzalloc(sizeof(S)); \
+ barrier(); \
+} while (0)
+#define DEINIT_S() do { \
+ free(test_ptr_to_statics); \
+} while (0)
+
+static number_t primary(enum token n);
+
+static void syntax(const char *op, const char *msg) NORETURN;
static void syntax(const char *op, const char *msg)
{
if (op && *op) {
- bb_error_msg_and_die("%s: %s", op, msg);
+ bb_error_msg("%s: %s", op, msg);
} else {
- bb_error_msg_and_die("%s", msg);
+ bb_error_msg("%s: %s"+4, msg);
}
+ longjmp(leaving, 2);
}
-static int oexpr(enum token n)
+/* atoi with error detection */
+//XXX: FIXME: duplicate of existing libbb function?
+static number_t getn(const char *s)
{
- int res;
+ char *p;
+#if ENABLE_FEATURE_TEST_64
+ long long r;
+#else
+ long r;
+#endif
- res = aexpr(n);
- if (t_lex(*++t_wp) == BOR) {
- return oexpr(t_lex(*++t_wp)) || res;
- }
- t_wp--;
- return res;
+ errno = 0;
+#if ENABLE_FEATURE_TEST_64
+ r = strtoll(s, &p, 10);
+#else
+ r = strtol(s, &p, 10);
+#endif
+
+ if (errno != 0)
+ syntax(s, "out of range");
+
+ if (*(skip_whitespace(p)))
+ syntax(s, "bad number");
+
+ return r;
}
-static int aexpr(enum token n)
+/* UNUSED
+static int newerf(const char *f1, const char *f2)
{
- int res;
+ struct stat b1, b2;
- res = nexpr(n);
- if (t_lex(*++t_wp) == BAND)
- return aexpr(t_lex(*++t_wp)) && res;
- t_wp--;
- return res;
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime);
}
-static int nexpr(enum token n)
+static int olderf(const char *f1, const char *f2)
{
- if (n == UNOT)
- return !nexpr(t_lex(*++t_wp));
- return primary(n);
+ struct stat b1, b2;
+
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime);
}
-static int primary(enum token n)
+static int equalf(const char *f1, const char *f2)
{
- int res;
+ struct stat b1, b2;
- if (n == EOI) {
- syntax(NULL, "argument expected");
- }
- if (n == LPAREN) {
- res = oexpr(t_lex(*++t_wp));
- if (t_lex(*++t_wp) != RPAREN)
- syntax(NULL, "closing paren expected");
- return res;
+ return (stat(f1, &b1) == 0 &&
+ stat(f2, &b2) == 0 &&
+ b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
+}
+*/
+
+
+static enum token check_operator(char *s)
+{
+ static const struct operator_t no_op = {
+ .op_num = -1,
+ .op_type = -1
+ };
+ const struct operator_t *op;
+
+ last_operator = &no_op;
+ if (s == NULL) {
+ return EOI;
}
- if (t_wp_op && t_wp_op->op_type == UNOP) {
- /* unary expression */
- if (*++t_wp == NULL)
- syntax(t_wp_op->op_text, "argument expected");
- switch (n) {
- case STREZ:
- return strlen(*t_wp) == 0;
- case STRNZ:
- return strlen(*t_wp) != 0;
- case FILTT:
- return isatty(getn(*t_wp));
- default:
- return filstat(*t_wp, n);
+
+ op = ops;
+ do {
+ if (strcmp(s, op->op_text) == 0) {
+ last_operator = op;
+ return op->op_num;
}
+ op++;
+ } while (op < ops + ARRAY_SIZE(ops));
+
+ return OPERAND;
+}
+
+
+static int binop(void)
+{
+ const char *opnd1, *opnd2;
+ const struct operator_t *op;
+ number_t val1, val2;
+
+ opnd1 = *args;
+ check_operator(*++args);
+ op = last_operator;
+
+ opnd2 = *++args;
+ if (opnd2 == NULL)
+ syntax(op->op_text, "argument expected");
+
+ if (is_int_op(op->op_num)) {
+ val1 = getn(opnd1);
+ val2 = getn(opnd2);
+ if (op->op_num == INTEQ)
+ return val1 == val2;
+ if (op->op_num == INTNE)
+ return val1 != val2;
+ if (op->op_num == INTGE)
+ return val1 >= val2;
+ if (op->op_num == INTGT)
+ return val1 > val2;
+ if (op->op_num == INTLE)
+ return val1 <= val2;
+ if (op->op_num == INTLT)
+ return val1 < val2;
+ }
+ if (is_str_op(op->op_num)) {
+ val1 = strcmp(opnd1, opnd2);
+ if (op->op_num == STREQ)
+ return val1 == 0;
+ if (op->op_num == STRNE)
+ return val1 != 0;
+ if (op->op_num == STRLT)
+ return val1 < 0;
+ if (op->op_num == STRGT)
+ return val1 > 0;
}
+ /* We are sure that these three are by now the only binops we didn't check
+ * yet, so we do not check if the class is correct:
+ */
+/* if (is_file_op(op->op_num)) */
+ {
+ struct stat b1, b2;
+
+ if (stat(opnd1, &b1) || stat(opnd2, &b2))
+ return 0; /* false, since at least one stat failed */
+ if (op->op_num == FILNT)
+ return b1.st_mtime > b2.st_mtime;
+ if (op->op_num == FILOT)
+ return b1.st_mtime < b2.st_mtime;
+ if (op->op_num == FILEQ)
+ return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
+ }
+ return 1; /* NOTREACHED */
+}
+
- if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
- return binop();
+static void initialize_group_array(void)
+{
+ ngroups = getgroups(0, NULL);
+ if (ngroups > 0) {
+ /* FIXME: ash tries so hard to not die on OOM,
+ * and we spoil it with just one xrealloc here */
+ /* We realloc, because test_main can be entered repeatedly by shell.
+ * Testcase (ash): 'while true; do test -x some_file; done'
+ * and watch top. (some_file must have owner != you) */
+ group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
+ getgroups(ngroups, group_array);
}
+}
- return strlen(*t_wp) > 0;
+
+/* Return non-zero if GID is one that we have in our groups list. */
+//XXX: FIXME: duplicate of existing libbb function?
+// see toplevel TODO file:
+// possible code duplication ingroup() and is_a_group_member()
+static int is_a_group_member(gid_t gid)
+{
+ int i;
+
+ /* Short-circuit if possible, maybe saving a call to getgroups(). */
+ if (gid == getgid() || gid == getegid())
+ return 1;
+
+ if (ngroups == 0)
+ initialize_group_array();
+
+ /* Search through the list looking for GID. */
+ for (i = 0; i < ngroups; i++)
+ if (gid == group_array[i])
+ return 1;
+
+ return 0;
}
-static int binop()
+
+/* Do the same thing access(2) does, but use the effective uid and gid,
+ and don't make the mistake of telling root that any file is
+ executable. */
+static int test_eaccess(char *path, int mode)
{
- const char *opnd1, *opnd2;
- struct t_op const *op;
+ struct stat st;
+ unsigned int euid = geteuid();
- opnd1 = *t_wp;
- (void) t_lex(*++t_wp);
- op = t_wp_op;
+ if (stat(path, &st) < 0)
+ return -1;
- if ((opnd2 = *++t_wp) == (char *) 0)
- syntax(op->op_text, "argument expected");
+ if (euid == 0) {
+ /* Root can read or write any file. */
+ if (mode != X_OK)
+ return 0;
- switch (op->op_num) {
- case STREQ:
- return strcmp(opnd1, opnd2) == 0;
- case STRNE:
- return strcmp(opnd1, opnd2) != 0;
- case STRLT:
- return strcmp(opnd1, opnd2) < 0;
- case STRGT:
- return strcmp(opnd1, opnd2) > 0;
- case INTEQ:
- return getn(opnd1) == getn(opnd2);
- case INTNE:
- return getn(opnd1) != getn(opnd2);
- case INTGE:
- return getn(opnd1) >= getn(opnd2);
- case INTGT:
- return getn(opnd1) > getn(opnd2);
- case INTLE:
- return getn(opnd1) <= getn(opnd2);
- case INTLT:
- return getn(opnd1) < getn(opnd2);
- case FILNT:
- return newerf(opnd1, opnd2);
- case FILOT:
- return olderf(opnd1, opnd2);
- case FILEQ:
- return equalf(opnd1, opnd2);
+ /* Root can execute any file that has any one of the execute
+ bits set. */
+ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+ return 0;
}
- /* NOTREACHED */
- return 1;
+
+ if (st.st_uid == euid) /* owner */
+ mode <<= 6;
+ else if (is_a_group_member(st.st_gid))
+ mode <<= 3;
+
+ if (st.st_mode & mode)
+ return 0;
+
+ return -1;
}
+
static int filstat(char *nm, enum token mode)
{
struct stat s;
- unsigned int i;
+ unsigned i = i; /* gcc 3.x thinks it can be used uninitialized */
if (mode == FILSYM) {
#ifdef S_IFLNK
@@ -359,187 +509,269 @@ static int filstat(char *nm, enum token mode)
if (stat(nm, &s) != 0)
return 0;
-
- switch (mode) {
- case FILRD:
- return test_eaccess(nm, R_OK) == 0;
- case FILWR:
- return test_eaccess(nm, W_OK) == 0;
- case FILEX:
- return test_eaccess(nm, X_OK) == 0;
- case FILEXIST:
+ if (mode == FILEXIST)
return 1;
- case FILREG:
- i = S_IFREG;
- goto filetype;
- case FILDIR:
- i = S_IFDIR;
- goto filetype;
- case FILCDEV:
- i = S_IFCHR;
- goto filetype;
- case FILBDEV:
- i = S_IFBLK;
- goto filetype;
- case FILFIFO:
+ if (is_file_access(mode)) {
+ if (mode == FILRD)
+ i = R_OK;
+ if (mode == FILWR)
+ i = W_OK;
+ if (mode == FILEX)
+ i = X_OK;
+ return test_eaccess(nm, i) == 0;
+ }
+ if (is_file_type(mode)) {
+ if (mode == FILREG)
+ i = S_IFREG;
+ if (mode == FILDIR)
+ i = S_IFDIR;
+ if (mode == FILCDEV)
+ i = S_IFCHR;
+ if (mode == FILBDEV)
+ i = S_IFBLK;
+ if (mode == FILFIFO) {
#ifdef S_IFIFO
- i = S_IFIFO;
- goto filetype;
+ i = S_IFIFO;
#else
- return 0;
+ return 0;
#endif
- case FILSOCK:
+ }
+ if (mode == FILSOCK) {
#ifdef S_IFSOCK
- i = S_IFSOCK;
- goto filetype;
+ i = S_IFSOCK;
#else
- return 0;
+ return 0;
#endif
- case FILSUID:
- i = S_ISUID;
- goto filebit;
- case FILSGID:
- i = S_ISGID;
- goto filebit;
- case FILSTCK:
- i = S_ISVTX;
- goto filebit;
- case FILGZ:
+ }
+ filetype:
+ return ((s.st_mode & S_IFMT) == i);
+ }
+ if (is_file_bit(mode)) {
+ if (mode == FILSUID)
+ i = S_ISUID;
+ if (mode == FILSGID)
+ i = S_ISGID;
+ if (mode == FILSTCK)
+ i = S_ISVTX;
+ return ((s.st_mode & i) != 0);
+ }
+ if (mode == FILGZ)
return s.st_size > 0L;
- case FILUID:
+ if (mode == FILUID)
return s.st_uid == geteuid();
- case FILGID:
+ if (mode == FILGID)
return s.st_gid == getegid();
- default:
- return 1;
- }
-
- filetype:
- return ((s.st_mode & S_IFMT) == i);
-
- filebit:
- return ((s.st_mode & i) != 0);
+ return 1; /* NOTREACHED */
}
-static enum token t_lex(char *s)
-{
- struct t_op const *op = ops;
- if (s == 0) {
- t_wp_op = (struct t_op *) 0;
- return EOI;
- }
- while (op->op_text) {
- if (strcmp(s, op->op_text) == 0) {
- t_wp_op = op;
- return op->op_num;
+static number_t nexpr(enum token n)
+{
+ number_t res;
+
+ nest_msg(">nexpr(%s)\n", TOKSTR[n]);
+ if (n == UNOT) {
+ n = check_operator(*++args);
+ if (n == EOI) {
+ /* special case: [ ! ], [ a -a ! ] are valid */
+ /* IOW, "! ARG" may miss ARG */
+ unnest_msg("<nexpr:1 (!EOI)\n");
+ return 1;
}
- op++;
+ res = !nexpr(n);
+ unnest_msg("<nexpr:%lld\n", res);
+ return res;
}
- t_wp_op = (struct t_op *) 0;
- return OPERAND;
+ res = primary(n);
+ unnest_msg("<nexpr:%lld\n", res);
+ return res;
}
-/* atoi with error detection */
-static int getn(const char *s)
-{
- char *p;
- long r;
-
- errno = 0;
- r = strtol(s, &p, 10);
-
- if (errno != 0)
- bb_error_msg_and_die("%s: out of range", s);
- /* p = bb_skip_whitespace(p); avoid const warning */
- if (*(bb_skip_whitespace(p)))
- bb_error_msg_and_die("%s: bad number", s);
-
- return (int) r;
-}
-
-static int newerf(const char *f1, const char *f2)
+static number_t aexpr(enum token n)
{
- struct stat b1, b2;
+ number_t res;
- return (stat(f1, &b1) == 0 &&
- stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime);
+ nest_msg(">aexpr(%s)\n", TOKSTR[n]);
+ res = nexpr(n);
+ dbg_msg("aexpr: nexpr:%lld, next args:%s\n", res, args[1]);
+ if (check_operator(*++args) == BAND) {
+ dbg_msg("aexpr: arg is AND, next args:%s\n", args[1]);
+ res = aexpr(check_operator(*++args)) && res;
+ unnest_msg("<aexpr:%lld\n", res);
+ return res;
+ }
+ args--;
+ unnest_msg("<aexpr:%lld, args:%s\n", res, args[0]);
+ return res;
}
-static int olderf(const char *f1, const char *f2)
-{
- struct stat b1, b2;
-
- return (stat(f1, &b1) == 0 &&
- stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime);
-}
-static int equalf(const char *f1, const char *f2)
+static number_t oexpr(enum token n)
{
- struct stat b1, b2;
+ number_t res;
- return (stat(f1, &b1) == 0 &&
- stat(f2, &b2) == 0 &&
- b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
+ nest_msg(">oexpr(%s)\n", TOKSTR[n]);
+ res = aexpr(n);
+ dbg_msg("oexpr: aexpr:%lld, next args:%s\n", res, args[1]);
+ if (check_operator(*++args) == BOR) {
+ dbg_msg("oexpr: next arg is OR, next args:%s\n", args[1]);
+ res = oexpr(check_operator(*++args)) || res;
+ unnest_msg("<oexpr:%lld\n", res);
+ return res;
+ }
+ args--;
+ unnest_msg("<oexpr:%lld, args:%s\n", res, args[0]);
+ return res;
}
-/* Do the same thing access(2) does, but use the effective uid and gid,
- and don't make the mistake of telling root that any file is
- executable. */
-static int test_eaccess(char *path, int mode)
+
+static number_t primary(enum token n)
{
- struct stat st;
- unsigned int euid = geteuid();
+#if TEST_DEBUG
+ number_t res = res; /* for compiler */
+#else
+ number_t res;
+#endif
+ const struct operator_t *args0_op;
- if (stat(path, &st) < 0)
- return (-1);
+ nest_msg(">primary(%s)\n", TOKSTR[n]);
+ if (n == EOI) {
+ syntax(NULL, "argument expected");
+ }
+ if (n == LPAREN) {
+ res = oexpr(check_operator(*++args));
+ if (check_operator(*++args) != RPAREN)
+ syntax(NULL, "closing paren expected");
+ unnest_msg("<primary:%lld\n", res);
+ return res;
+ }
- if (euid == 0) {
- /* Root can read or write any file. */
- if (mode != X_OK)
- return (0);
+ /* coreutils 6.9 checks "is args[1] binop and args[2] exist?" first,
+ * do the same */
+ args0_op = last_operator;
+ /* last_operator = operator at args[1] */
+ if (check_operator(args[1]) != EOI) { /* if args[1] != NULL */
+ if (args[2]) {
+ // coreutils also does this:
+ // if (args[3] && args[0]="-l" && args[2] is BINOP)
+ // return binop(1 /* prepended by -l */);
+ if (last_operator->op_type == BINOP)
+ unnest_msg_and_return(binop(), "<primary: binop:%lld\n");
+ }
+ }
+ /* check "is args[0] unop?" second */
+ if (args0_op->op_type == UNOP) {
+ /* unary expression */
+ if (args[1] == NULL)
+// syntax(args0_op->op_text, "argument expected");
+ goto check_emptiness;
+ args++;
+ if (n == STREZ)
+ unnest_msg_and_return(args[0][0] == '\0', "<primary:%lld\n");
+ if (n == STRNZ)
+ unnest_msg_and_return(args[0][0] != '\0', "<primary:%lld\n");
+ if (n == FILTT)
+ unnest_msg_and_return(isatty(getn(*args)), "<primary: isatty(%s)%lld\n", *args);
+ unnest_msg_and_return(filstat(*args, n), "<primary: filstat(%s):%lld\n", *args);
+ }
- /* Root can execute any file that has any one of the execute
- bits set. */
- if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
- return (0);
+ /*check_operator(args[1]); - already done */
+ if (last_operator->op_type == BINOP) {
+ /* args[2] is known to be NULL, isn't it bound to fail? */
+ unnest_msg_and_return(binop(), "<primary:%lld\n");
}
+ check_emptiness:
+ unnest_msg_and_return(args[0][0] != '\0', "<primary:%lld\n");
+}
- if (st.st_uid == euid) /* owner */
- mode <<= 6;
- else if (is_a_group_member(st.st_gid))
- mode <<= 3;
- if (st.st_mode & mode)
- return (0);
+int test_main(int argc, char **argv)
+{
+ int res;
+ const char *arg0;
+// bool negate = 0;
+
+ arg0 = bb_basename(argv[0]);
+ if (arg0[0] == '[') {
+ --argc;
+ if (!arg0[1]) { /* "[" ? */
+ if (NOT_LONE_CHAR(argv[argc], ']')) {
+ bb_error_msg("missing ]");
+ return 2;
+ }
+ } else { /* assuming "[[" */
+ if (strcmp(argv[argc], "]]") != 0) {
+ bb_error_msg("missing ]]");
+ return 2;
+ }
+ }
+ argv[argc] = NULL;
+ }
- return (-1);
-}
+ /* We must do DEINIT_S() prior to returning */
+ INIT_S();
-static void initialize_group_array()
-{
- ngroups = getgroups(0, NULL);
- group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
- getgroups(ngroups, group_array);
-}
+ res = setjmp(leaving);
+ if (res)
+ goto ret;
-/* Return non-zero if GID is one that we have in our groups list. */
-static int is_a_group_member(gid_t gid)
-{
- register int i;
+ /* resetting ngroups is probably unnecessary. it will
+ * force a new call to getgroups(), which prevents using
+ * group data fetched during a previous call. but the
+ * only way the group data could be stale is if there's
+ * been an intervening call to setgroups(), and this
+ * isn't likely in the case of a shell. paranoia
+ * prevails...
+ */
+ ngroups = 0;
- /* Short-circuit if possible, maybe saving a call to getgroups(). */
- if (gid == getgid() || gid == getegid())
- return (1);
+ //argc--;
+ argv++;
- if (ngroups == 0)
- initialize_group_array();
+ /* Implement special cases from POSIX.2, section 4.62.4 */
+ if (!argv[0]) { /* "test" */
+ res = 1;
+ goto ret;
+ }
+#if 0
+// Now it's fixed in the parser and should not be needed
+ if (LONE_CHAR(argv[0], '!') && argv[1]) {
+ negate = 1;
+ //argc--;
+ argv++;
+ }
+ if (!argv[1]) { /* "test [!] arg" */
+ res = (*argv[0] == '\0');
+ goto ret;
+ }
+ if (argv[2] && !argv[3]) {
+ check_operator(argv[1]);
+ if (last_operator->op_type == BINOP) {
+ /* "test [!] arg1 <binary_op> arg2" */
+ args = argv;
+ res = (binop() == 0);
+ goto ret;
+ }
+ }
- /* Search through the list looking for GID. */
- for (i = 0; i < ngroups; i++)
- if (gid == group_array[i])
- return (1);
+ /* Some complex expression. Undo '!' removal */
+ if (negate) {
+ negate = 0;
+ //argc++;
+ argv--;
+ }
+#endif
+ args = argv;
+ res = !oexpr(check_operator(*args));
- return (0);
+ if (*args != NULL && *++args != NULL) {
+ /* TODO: example when this happens? */
+ bb_error_msg("%s: unknown operand", *args);
+ res = 2;
+ }
+ ret:
+ DEINIT_S();
+// return negate ? !res : res;
+ return res;
}
diff --git a/release/src/router/busybox/coreutils/test_ptr_hack.c b/release/src/router/busybox/coreutils/test_ptr_hack.c
new file mode 100644
index 00000000..a05203d6
--- /dev/null
+++ b/release/src/router/busybox/coreutils/test_ptr_hack.c
@@ -0,0 +1,23 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2008 by Denys Vlasenko <vda.linux@googlemail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+struct test_statics;
+
+#ifndef GCC_COMBINE
+
+/* We cheat here. It is declared as const ptr in libbb.h,
+ * but here we make it live in R/W memory */
+struct test_statics *test_ptr_to_statics;
+
+#else
+
+/* gcc -combine will see through and complain */
+/* Using alternative method which is more likely to break
+ * on weird architectures, compilers, linkers and so on */
+struct test_statics *const test_ptr_to_statics __attribute__ ((section (".data")));
+
+#endif
diff --git a/release/src/router/busybox/coreutils/touch.c b/release/src/router/busybox/coreutils/touch.c
index 3d780e16..20191546 100644
--- a/release/src/router/busybox/coreutils/touch.c
+++ b/release/src/router/busybox/coreutils/touch.c
@@ -2,22 +2,9 @@
/*
* Mini touch implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m, -r, -t not supported. */
@@ -30,33 +17,73 @@
* Also, exiting on a failure was a bug. All args should be processed.
*/
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
-extern int touch_main(int argc, char **argv)
+/* This is a NOFORK applet. Be very careful! */
+
+/* coreutils implements:
+ * -a change only the access time
+ * -c, --no-create
+ * do not create any files
+ * -d, --date=STRING
+ * parse STRING and use it instead of current time
+ * -f (ignored, BSD compat)
+ * -m change only the modification time
+ * -r, --reference=FILE
+ * use this file's times instead of current time
+ * -t STAMP
+ * use [[CC]YY]MMDDhhmm[.ss] instead of current time
+ * --time=WORD
+ * change the specified time: WORD is access, atime, or use
+ */
+
+int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int touch_main(int argc UNUSED_PARAM, char **argv)
{
+#if ENABLE_DESKTOP
+#if ENABLE_GETOPT_LONG
+ static const char longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "no-create\0" No_argument "c"
+ "reference\0" Required_argument "r"
+ ;
+#endif
+ struct utimbuf timebuf;
+ char *reference_file = NULL;
+#else
+#define reference_file NULL
+#define timebuf (*(struct utimbuf*)NULL)
+#endif
int fd;
- int flags;
int status = EXIT_SUCCESS;
+ int opts;
- flags = bb_getopt_ulflags(argc, argv, "c");
+#if ENABLE_DESKTOP
+#if ENABLE_GETOPT_LONG
+ applet_long_options = longopts;
+#endif
+#endif
+ opts = getopt32(argv, "c" USE_DESKTOP("r:")
+ /*ignored:*/ "fma"
+ USE_DESKTOP(, &reference_file));
+ opts &= 1; /* only -c bit is left */
argv += optind;
-
if (!*argv) {
bb_show_usage();
}
+ if (reference_file) {
+ struct stat stbuf;
+ xstat(reference_file, &stbuf);
+ timebuf.actime = stbuf.st_atime;
+ timebuf.modtime = stbuf.st_mtime;
+ }
+
do {
- if (utime(*argv, NULL)) {
- if (errno == ENOENT) { /* no such file*/
- if (flags & 1) { /* Creation is disabled, so ignore. */
+ if (utime(*argv, reference_file ? &timebuf : NULL)) {
+ if (errno == ENOENT) { /* no such file */
+ if (opts) { /* creation is disabled, so ignore */
continue;
}
/* Try to create the file. */
@@ -64,11 +91,13 @@ extern int touch_main(int argc, char **argv)
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
);
if ((fd >= 0) && !close(fd)) {
+ if (reference_file)
+ utime(*argv, &timebuf);
continue;
}
}
status = EXIT_FAILURE;
- bb_perror_msg("%s", *argv);
+ bb_simple_perror_msg(*argv);
}
} while (*++argv);
diff --git a/release/src/router/busybox/coreutils/tr.c b/release/src/router/busybox/coreutils/tr.c
index 4e69dc89..d89b80be 100644
--- a/release/src/router/busybox/coreutils/tr.c
+++ b/release/src/router/busybox/coreutils/tr.c
@@ -2,247 +2,298 @@
/*
* Mini tr implementation for busybox
*
- * Copyright (c) Michiel Huisjes
+ ** Copyright (c) 1987,1997, Prentice Hall All rights reserved.
*
- * This version of tr is adapted from Minix tr and was modified
- * by Erik Andersen <andersen@codepoet.org> to be used in busybox.
+ * The name of Prentice Hall may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
*
- * 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.
+ * Copyright (c) Michiel Huisjes
*
- * 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.
+ * This version of tr is adapted from Minix tr and was modified
+ * by Erik Andersen <andersen@codepoet.org> to be used in busybox.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
+/* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
+ * TODO: graph, print
+ */
+#include "libbb.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include "busybox.h"
-
-/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
- * enabled, we otherwise get a "storage size isn't constant error. */
-#define ASCII 0377
-
-/* some "globals" shared across this file */
-static char com_fl, del_fl, sq_fl;
-static short in_index, out_index;
-/* these last are pointers to static buffers declared in tr_main */
-static unsigned char *poutput, *pinput;
-static unsigned char *pvector;
-static char *pinvec, *poutvec;
-
-
-static void convert(void)
-{
- short read_chars = 0;
- short c, coded;
- short last = -1;
-
- for (;;) {
- if (in_index == read_chars) {
- if ((read_chars = read(0, (char *) pinput, BUFSIZ)) <= 0) {
- if (write(1, (char *) poutput, out_index) != out_index)
- bb_error_msg(bb_msg_write_error);
- exit(0);
- }
- in_index = 0;
- }
- c = pinput[in_index++];
- coded = pvector[c];
- if (del_fl && pinvec[c])
- continue;
- if (sq_fl && last == coded && (pinvec[c] || poutvec[coded]))
- continue;
- poutput[out_index++] = last = coded;
- if (out_index == BUFSIZ) {
- if (write(1, (char *) poutput, out_index) != out_index)
- bb_error_msg_and_die(bb_msg_write_error);
- out_index = 0;
- }
- }
-
- /* NOTREACHED */
-}
+enum {
+ ASCII = 256,
+ /* string buffer needs to be at least as big as the whole "alphabet".
+ * BUFSIZ == ASCII is ok, but we will realloc in expand
+ * even for smallest patterns, let's avoid that by using *2:
+ */
+ TR_BUFSIZ = (BUFSIZ > ASCII*2) ? BUFSIZ : ASCII*2,
+};
-static void map(register unsigned char *string1, unsigned int string1_len,
- register unsigned char *string2, unsigned int string2_len)
+static void map(char *pvector,
+ char *string1, unsigned string1_len,
+ char *string2, unsigned string2_len)
{
- unsigned char last = '0';
- unsigned int i, j;
+ char last = '0';
+ unsigned i, j;
for (j = 0, i = 0; i < string1_len; i++) {
if (string2_len <= j)
- pvector[string1[i]] = last;
+ pvector[(unsigned char)(string1[i])] = last;
else
- pvector[string1[i]] = last = string2[j++];
+ pvector[(unsigned char)(string1[i])] = last = string2[j++];
}
}
/* supported constructs:
- * Ranges, e.g., [0-9] ==> 0123456789
- * Escapes, e.g., \a ==> Control-G
+ * Ranges, e.g., 0-9 ==> 0123456789
+ * Escapes, e.g., \a ==> Control-G
+ * Character classes, e.g. [:upper:] ==> A...Z
+ * Equiv classess, e.g. [=A=] ==> A (hmmmmmmm?)
+ * not supported:
+ * \ooo-\ooo - octal ranges
+ * [x*N] - repeat char x N times
+ * [x*] - repeat char x until it fills STRING2:
+ * # echo qwe123 | /usr/bin/tr 123456789 '[d]'
+ * qwe[d]
+ * # echo qwe123 | /usr/bin/tr 123456789 '[d*]'
+ * qweddd
*/
-static unsigned int expand(const char *arg, register unsigned char *buffer)
+static unsigned expand(const char *arg, char **buffer_p)
{
- unsigned char *buffer_start = buffer;
- int i, ac;
+ char *buffer = *buffer_p;
+ unsigned pos = 0;
+ unsigned size = TR_BUFSIZ;
+ unsigned i; /* can't be unsigned char: must be able to hold 256 */
+ unsigned char ac;
while (*arg) {
+ if (pos + ASCII > size) {
+ size += ASCII;
+ *buffer_p = buffer = xrealloc(buffer, size);
+ }
if (*arg == '\\') {
arg++;
- *buffer++ = bb_process_escape_sequence(&arg);
- } else if (*(arg+1) == '-') {
- ac = *(arg+2);
- if(ac == 0) {
- *buffer++ = *arg++;
- continue;
+ buffer[pos++] = bb_process_escape_sequence(&arg);
+ continue;
+ }
+ if (arg[1] == '-') { /* "0-9..." */
+ ac = arg[2];
+ if (ac == '\0') { /* "0-": copy verbatim */
+ buffer[pos++] = *arg++; /* copy '0' */
+ continue; /* next iter will copy '-' and stop */
}
- i = *arg;
- while (i <= ac)
- *buffer++ = i++;
- arg += 3; /* Skip the assumed a-z */
- } else if (*arg == '[') {
+ i = (unsigned char) *arg;
+ while (i <= ac) /* ok: i is unsigned _int_ */
+ buffer[pos++] = i++;
+ arg += 3; /* skip 0-9 */
+ continue;
+ }
+ if ((ENABLE_FEATURE_TR_CLASSES || ENABLE_FEATURE_TR_EQUIV)
+ && *arg == '['
+ ) {
arg++;
- i = *arg++;
- if (*arg++ != '-') {
- *buffer++ = '[';
- arg -= 2;
+ i = (unsigned char) *arg++;
+ /* "[xyz...". i=x, arg points to y */
+ if (ENABLE_FEATURE_TR_CLASSES && i == ':') { /* [:class:] */
+#define CLO ":]\0"
+ static const char classes[] ALIGN1 =
+ "alpha"CLO "alnum"CLO "digit"CLO
+ "lower"CLO "upper"CLO "space"CLO
+ "blank"CLO "punct"CLO "cntrl"CLO
+ "xdigit"CLO;
+ enum {
+ CLASS_invalid = 0, /* we increment the retval */
+ CLASS_alpha = 1,
+ CLASS_alnum = 2,
+ CLASS_digit = 3,
+ CLASS_lower = 4,
+ CLASS_upper = 5,
+ CLASS_space = 6,
+ CLASS_blank = 7,
+ CLASS_punct = 8,
+ CLASS_cntrl = 9,
+ CLASS_xdigit = 10,
+ //CLASS_graph = 11,
+ //CLASS_print = 12,
+ };
+ smalluint j;
+ char *tmp;
+
+ /* xdigit needs 8, not 7 */
+ i = 7 + (arg[0] == 'x');
+ tmp = xstrndup(arg, i);
+ j = index_in_strings(classes, tmp) + 1;
+ free(tmp);
+
+ if (j == CLASS_invalid)
+ goto skip_bracket;
+
+ arg += i;
+ if (j == CLASS_alnum || j == CLASS_digit || j == CLASS_xdigit) {
+ for (i = '0'; i <= '9'; i++)
+ buffer[pos++] = i;
+ }
+ if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) {
+ for (i = 'A'; i <= 'Z'; i++)
+ buffer[pos++] = i;
+ }
+ if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) {
+ for (i = 'a'; i <= 'z'; i++)
+ buffer[pos++] = i;
+ }
+ if (j == CLASS_space || j == CLASS_blank) {
+ buffer[pos++] = '\t';
+ if (j == CLASS_space) {
+ buffer[pos++] = '\n';
+ buffer[pos++] = '\v';
+ buffer[pos++] = '\f';
+ buffer[pos++] = '\r';
+ }
+ buffer[pos++] = ' ';
+ }
+ if (j == CLASS_punct || j == CLASS_cntrl) {
+ for (i = '\0'; i < ASCII; i++) {
+ if ((j == CLASS_punct && isprint(i) && !isalnum(i) && !isspace(i))
+ || (j == CLASS_cntrl && iscntrl(i))
+ ) {
+ buffer[pos++] = i;
+ }
+ }
+ }
+ if (j == CLASS_xdigit) {
+ for (i = 'A'; i <= 'F'; i++) {
+ buffer[pos + 6] = i | 0x20;
+ buffer[pos++] = i;
+ }
+ pos += 6;
+ }
+ continue;
+ }
+ /* "[xyz...", i=x, arg points to y */
+ if (ENABLE_FEATURE_TR_EQUIV && i == '=') { /* [=CHAR=] */
+ buffer[pos++] = *arg; /* copy CHAR */
+ if (!arg[0] || arg[1] != '=' || arg[2] != ']')
+ bb_show_usage();
+ arg += 3; /* skip CHAR=] */
continue;
}
- ac = *arg++;
- while (i <= ac)
- *buffer++ = i++;
- arg++; /* Skip the assumed ']' */
- } else
- *buffer++ = *arg++;
+ /* The rest of "[xyz..." cases is treated as normal
+ * string, "[" has no special meaning here:
+ * tr "[a-z]" "[A-Z]" can be written as tr "a-z" "A-Z",
+ * also try tr "[a-z]" "_A-Z+" and you'll see that
+ * [] is not special here.
+ */
+ skip_bracket:
+ arg -= 2; /* points to "[" in "[xyz..." */
+ }
+ buffer[pos++] = *arg++;
}
-
- return (buffer - buffer_start);
+ return pos;
}
-static int complement(unsigned char *buffer, int buffer_len)
+/* NB: buffer is guaranteed to be at least TR_BUFSIZE
+ * (which is >= ASCII) big.
+ */
+static int complement(char *buffer, int buffer_len)
{
- register short i, j, ix;
- char conv[ASCII + 2];
+ int len;
+ char conv[ASCII];
+ unsigned char ch;
- ix = 0;
- for (i = 0; i <= ASCII; i++) {
- for (j = 0; j < buffer_len; j++)
- if (buffer[j] == i)
- break;
- if (j == buffer_len)
- conv[ix++] = i & ASCII;
+ len = 0;
+ ch = '\0';
+ while (1) {
+ if (memchr(buffer, ch, buffer_len) == NULL)
+ conv[len++] = ch;
+ if (++ch == '\0')
+ break;
}
- memcpy(buffer, conv, ix);
- return ix;
+ memcpy(buffer, conv, len);
+ return len;
}
-extern int tr_main(int argc, char **argv)
+int tr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tr_main(int argc UNUSED_PARAM, char **argv)
{
- register unsigned char *ptr;
- int output_length=0, input_length;
- int idx = 1;
int i;
- RESERVE_CONFIG_BUFFER(output, BUFSIZ);
- RESERVE_CONFIG_BUFFER(input, BUFSIZ);
- RESERVE_CONFIG_UBUFFER(vector, ASCII+1);
- RESERVE_CONFIG_BUFFER(invec, ASCII+1);
- RESERVE_CONFIG_BUFFER(outvec, ASCII+1);
-
- /* ... but make them available globally */
- poutput = output;
- pinput = input;
- pvector = vector;
- pinvec = invec;
- poutvec = outvec;
-
- if (argc > 1 && argv[idx][0] == '-') {
- for (ptr = (unsigned char *) &argv[idx][1]; *ptr; ptr++) {
- switch (*ptr) {
- case 'c':
- com_fl = TRUE;
- break;
- case 'd':
- del_fl = TRUE;
- break;
- case 's':
- sq_fl = TRUE;
- break;
- default:
- bb_show_usage();
- }
- }
- idx++;
- }
- for (i = 0; i <= ASCII; i++) {
+ smalluint opts;
+ ssize_t read_chars;
+ size_t in_index, out_index;
+ unsigned last = UCHAR_MAX + 1; /* not equal to any char */
+ unsigned char coded, c;
+ char *str1 = xmalloc(TR_BUFSIZ);
+ char *str2 = xmalloc(TR_BUFSIZ);
+ int str2_length;
+ int str1_length;
+ char *vector = xzalloc(ASCII * 3);
+ char *invec = vector + ASCII;
+ char *outvec = vector + ASCII * 2;
+
+#define TR_OPT_complement (3 << 0)
+#define TR_OPT_delete (1 << 2)
+#define TR_OPT_squeeze_reps (1 << 3)
+
+ for (i = 0; i < ASCII; i++) {
vector[i] = i;
- invec[i] = outvec[i] = FALSE;
+ /*invec[i] = outvec[i] = FALSE; - done by xzalloc */
}
- if (argv[idx] != NULL) {
- input_length = expand(argv[idx++], input);
- if (com_fl)
- input_length = complement(input, input_length);
- if (argv[idx] != NULL) {
- if (*argv[idx] == '\0')
- bb_error_msg_and_die("STRING2 cannot be empty");
- output_length = expand(argv[idx], output);
- map(input, input_length, output, output_length);
- }
- for (i = 0; i < input_length; i++)
- invec[(int)input[i]] = TRUE;
- for (i = 0; i < output_length; i++)
- outvec[(int)output[i]] = TRUE;
+ /* -C/-c difference is that -C complements "characters",
+ * and -c complements "values" (binary bytes I guess).
+ * In POSIX locale, these are the same.
+ */
+
+ opt_complementary = "-1";
+ opts = getopt32(argv, "+Ccds"); /* '+': stop at first non-option */
+ argv += optind;
+
+ str1_length = expand(*argv++, &str1);
+ str2_length = 0;
+ if (opts & TR_OPT_complement)
+ str1_length = complement(str1, str1_length);
+ if (*argv) {
+ if (argv[0][0] == '\0')
+ bb_error_msg_and_die("STRING2 cannot be empty");
+ str2_length = expand(*argv, &str2);
+ map(vector, str1, str1_length,
+ str2, str2_length);
}
- convert();
- return (0);
-}
+ for (i = 0; i < str1_length; i++)
+ invec[(unsigned char)(str1[i])] = TRUE;
+ for (i = 0; i < str2_length; i++)
+ outvec[(unsigned char)(str2[i])] = TRUE;
-/*
- * Copyright (c) 1987,1997, Prentice Hall
- * All rights reserved.
- *
- * Redistribution and use of the MINIX operating system in source and
- * binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * Neither the name of Prentice Hall nor the names of the software
- * authors or contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
+ goto start_from;
+
+ /* In this loop, str1 space is reused as input buffer,
+ * str2 - as output one. */
+ for (;;) {
+ /* If we're out of input, flush output and read more input. */
+ if ((ssize_t)in_index == read_chars) {
+ if (out_index) {
+ xwrite(STDOUT_FILENO, str2, out_index);
+ start_from:
+ out_index = 0;
+ }
+ read_chars = safe_read(STDIN_FILENO, str1, TR_BUFSIZ);
+ if (read_chars <= 0) {
+ if (read_chars < 0)
+ bb_perror_msg_and_die(bb_msg_read_error);
+ break;
+ }
+ in_index = 0;
+ }
+ c = str1[in_index++];
+ if ((opts & TR_OPT_delete) && invec[c])
+ continue;
+ coded = vector[c];
+ if ((opts & TR_OPT_squeeze_reps) && last == coded
+ && (invec[c] || outvec[coded])
+ ) {
+ continue;
+ }
+ str2[out_index++] = last = coded;
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/release/src/router/busybox/coreutils/true.c b/release/src/router/busybox/coreutils/true.c
index d19e749a..8a7e6ae9 100644
--- a/release/src/router/busybox/coreutils/true.c
+++ b/release/src/router/busybox/coreutils/true.c
@@ -2,31 +2,20 @@
/*
* Mini true implementation for busybox
*
- * Copyright (C) 1999-2003 by Erik Andersen <andersen@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/true.html */
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int true_main(int argc, char **argv)
+int true_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int true_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/coreutils/tty.c b/release/src/router/busybox/coreutils/tty.c
index cd2c784f..d49fb50b 100644
--- a/release/src/router/busybox/coreutils/tty.c
+++ b/release/src/router/busybox/coreutils/tty.c
@@ -4,55 +4,41 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/tty.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-extern int tty_main(int argc, char **argv)
+int tty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int tty_main(int argc, char **argv SKIP_INCLUDE_SUSv2(UNUSED_PARAM))
{
const char *s;
- int silent; /* Note: No longer relevant in SUSv3. */
+ USE_INCLUDE_SUSv2(int silent;) /* Note: No longer relevant in SUSv3. */
int retval;
- bb_default_error_retval = 2; /* SUSv3 requires > 1 for error. */
+ xfunc_error_retval = 2; /* SUSv3 requires > 1 for error. */
- silent = bb_getopt_ulflags(argc, argv, "s");
+ USE_INCLUDE_SUSv2(silent = getopt32(argv, "s");)
+ USE_INCLUDE_SUSv2(argc -= optind;)
+ SKIP_INCLUDE_SUSv2(argc -= 1;)
/* gnu tty outputs a warning that it is ignoring all args. */
- bb_warn_ignoring_args(argc - optind);
+ bb_warn_ignoring_args(argc);
retval = 0;
- if ((s = ttyname(0)) == NULL) {
- /* According to SUSv3, ttyname can on fail with EBADF or ENOTTY.
+ s = xmalloc_ttyname(0);
+ if (s == NULL) {
+ /* According to SUSv3, ttyname can fail with EBADF or ENOTTY.
* We know the file descriptor is good, so failure means not a tty. */
s = "not a tty";
retval = 1;
}
+ USE_INCLUDE_SUSv2(if (!silent) puts(s);)
+ SKIP_INCLUDE_SUSv2(puts(s);)
- if (!silent) {
- puts(s);
- }
-
- bb_fflush_stdout_and_exit(retval);
+ fflush_stdout_and_exit(retval);
}
diff --git a/release/src/router/busybox/coreutils/uname.c b/release/src/router/busybox/coreutils/uname.c
index a3e52e39..33d026f1 100644
--- a/release/src/router/busybox/coreutils/uname.c
+++ b/release/src/router/busybox/coreutils/uname.c
@@ -1,118 +1,154 @@
/* vi: set sw=4 ts=4: */
/* uname -- print system information
- Copyright (C) 1989-1999 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ * Copyright (C) 1989-1999 Free Software Foundation, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/uname.html */
/* Option Example
+ * -s, --sysname SunOS
+ * -n, --nodename rocky8
+ * -r, --release 4.0
+ * -v, --version
+ * -m, --machine sun
+ * -a, --all SunOS rocky8 4.0 sun
+ *
+ * The default behavior is equivalent to '-s'.
+ *
+ * David MacKenzie <djm@gnu.ai.mit.edu>
+ *
+ * GNU coreutils 6.10:
+ * Option: struct Example(s):
+ * utsname
+ * field:
+ * -s, --kernel-name sysname Linux
+ * -n, --nodename nodename localhost.localdomain
+ * -r, --kernel-release release 2.6.29
+ * -v, --kernel-version version #1 SMP Sun Jan 11 20:52:37 EST 2009
+ * -m, --machine machine x86_64 i686
+ * -p, --processor (none) x86_64 i686
+ * -i, --hardware-platform (none) x86_64 i386
+ * NB: vanilla coreutils reports "unknown" -p and -i,
+ * x86_64 and i686/i386 shown above are Fedora's inventions.
+ * -o, --operating-system (none) GNU/Linux
+ * -a, --all: all of the above, in the order shown.
+ * If -p or -i is not known, don't show them
+ */
- -s, --sysname SunOS
- -n, --nodename rocky8
- -r, --release 4.0
- -v, --version
- -m, --machine sun
- -a, --all SunOS rocky8 4.0 sun
-
- The default behavior is equivalent to `-s'.
-
- David MacKenzie <djm@gnu.ai.mit.edu> */
-
-/* Busyboxed by Erik Andersen */
-
-/* Further size reductions by Glenn McGrath and Manuel Novoa III. */
-
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
+/* Busyboxed by Erik Andersen
*
- * Now does proper error checking on i/o. Plus some further space savings.
+ * Before 2003: Glenn McGrath and Manuel Novoa III
+ * Further size reductions.
+ * Mar 16, 2003: Manuel Novoa III (mjn3@codepoet.org)
+ * Now does proper error checking on i/o. Plus some further space savings.
+ * Jan 2009:
+ * Fix handling of -a to not print "unknown", add -o and -i support.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
#include <sys/utsname.h>
-#include "busybox.h"
+#include "libbb.h"
typedef struct {
struct utsname name;
- char processor[8]; /* for "unknown" */
+ char processor[sizeof(((struct utsname*)NULL)->machine)];
+ char platform[sizeof(((struct utsname*)NULL)->machine)];
+ char os[sizeof("GNU/Linux")];
} uname_info_t;
-static const char options[] = "snrvmpa";
-static const unsigned short int utsname_offset[] = {
- offsetof(uname_info_t,name.sysname),
- offsetof(uname_info_t,name.nodename),
- offsetof(uname_info_t,name.release),
- offsetof(uname_info_t,name.version),
- offsetof(uname_info_t,name.machine),
- offsetof(uname_info_t,processor)
+static const char options[] ALIGN1 = "snrvmpioa";
+static const unsigned short utsname_offset[] = {
+ offsetof(uname_info_t, name.sysname), /* -s */
+ offsetof(uname_info_t, name.nodename), /* -n */
+ offsetof(uname_info_t, name.release), /* -r */
+ offsetof(uname_info_t, name.version), /* -v */
+ offsetof(uname_info_t, name.machine), /* -m */
+ offsetof(uname_info_t, processor), /* -p */
+ offsetof(uname_info_t, platform), /* -i */
+ offsetof(uname_info_t, os), /* -o */
};
-int uname_main(int argc, char **argv)
+int uname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uname_main(int argc UNUSED_PARAM, char **argv)
{
+#if ENABLE_GETOPT_LONG
+ static const char longopts[] ALIGN1 =
+ /* name, has_arg, val */
+ "all\0" No_argument "a"
+ "kernel-name\0" No_argument "s"
+ "nodename\0" No_argument "n"
+ "kernel-release\0" No_argument "r"
+ "release\0" No_argument "r"
+ "kernel-version\0" No_argument "v"
+ "machine\0" No_argument "m"
+ "processor\0" No_argument "p"
+ "hardware-platform\0" No_argument "i"
+ "operating-system\0" No_argument "o"
+ ;
+#endif
uname_info_t uname_info;
#if defined(__sparc__) && defined(__linux__)
char *fake_sparc = getenv("FAKE_SPARC");
#endif
- const unsigned short int *delta;
- char toprint;
+ const char *unknown_str = "unknown";
+ const char *fmt;
+ const unsigned short *delta;
+ unsigned toprint;
- toprint = bb_getopt_ulflags(argc, argv, options);
+ USE_GETOPT_LONG(applet_long_options = longopts);
+ toprint = getopt32(argv, options);
- if (argc != optind) {
+ if (argv[optind]) { /* coreutils-6.9 compat */
bb_show_usage();
}
- if (toprint & (1 << 6)) {
- toprint = 0x3f;
+ if (toprint & (1 << 8)) { /* -a => all opts on */
+ toprint = (1 << 8) - 1;
+ unknown_str = ""; /* -a does not print unknown fields */
}
- if (toprint == 0) {
- toprint = 1; /* sysname */
+ if (toprint == 0) { /* no opts => -s (sysname) */
+ toprint = 1;
}
- if (uname(&uname_info.name) == -1) {
- bb_error_msg_and_die("cannot get system name");
- }
+ uname(&uname_info.name); /* never fails */
#if defined(__sparc__) && defined(__linux__)
- if ((fake_sparc != NULL)
- && ((fake_sparc[0] == 'y')
- || (fake_sparc[0] == 'Y'))) {
+ if (fake_sparc && (fake_sparc[0] | 0x20) == 'y') {
strcpy(uname_info.name.machine, "sparc");
}
#endif
+ strcpy(uname_info.processor, unknown_str);
+ strcpy(uname_info.platform, unknown_str);
+ strcpy(uname_info.os, "GNU/Linux");
+#if 0
+ /* Fedora does something like this */
+ strcpy(uname_info.processor, uname_info.name.machine);
+ strcpy(uname_info.platform, uname_info.name.machine);
+ if (uname_info.platform[0] == 'i'
+ && uname_info.platform[1]
+ && uname_info.platform[2] == '8'
+ && uname_info.platform[3] == '6'
+ ) {
+ uname_info.platform[1] = '3';
+ }
+#endif
- strcpy(uname_info.processor, "unknown");
-
- delta=utsname_offset;
+ delta = utsname_offset;
+ fmt = " %s" + 1;
do {
if (toprint & 1) {
- bb_printf(((char *)(&uname_info)) + *delta);
- if (toprint > 1) {
- putchar(' ');
+ const char *p = (char *)(&uname_info) + *delta;
+ if (p[0]) {
+ printf(fmt, p);
+ fmt = " %s";
}
}
++delta;
} while (toprint >>= 1);
- putchar('\n');
+ bb_putchar('\n');
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ fflush_stdout_and_exit(EXIT_SUCCESS); /* coreutils-6.9 compat */
}
diff --git a/release/src/router/busybox/coreutils/uniq.c b/release/src/router/busybox/coreutils/uniq.c
index 90686c9a..126eaeef 100644
--- a/release/src/router/busybox/coreutils/uniq.c
+++ b/release/src/router/busybox/coreutils/uniq.c
@@ -2,111 +2,101 @@
/*
* uniq implementation for busybox
*
- * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org>
*
+ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
*/
/* BB_AUDIT SUSv3 compliant */
/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include "busybox.h"
-#include "libcoreutils/coreutils.h"
+#include "libbb.h"
+
+static FILE *xgetoptfile_uniq_s(char **argv, int read0write2)
+{
+ const char *n;
-static const char uniq_opts[] = "f:s:cdu\0\7\3\5\1\2\4";
+ n = *argv;
+ if (n != NULL) {
+ if ((*n != '-') || n[1]) {
+ return xfopen(n, "r\0w" + read0write2);
+ }
+ }
+ return (read0write2) ? stdout : stdin;
+}
-int uniq_main(int argc, char **argv)
+int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uniq_main(int argc UNUSED_PARAM, char **argv)
{
FILE *in, *out;
- /* Note: Ignore the warning about dups and e0 possibly being uninitialized.
- * They will be initialized on the fist pass of the loop (since s0 is NULL). */
- unsigned long dups, skip_fields, skip_chars, i;
const char *s0, *e0, *s1, *e1, *input_filename;
- int opt;
- int uniq_flags = 6; /* -u */
+ unsigned long dups;
+ unsigned skip_fields, skip_chars, max_chars;
+ unsigned opt;
+ unsigned i;
+
+ enum {
+ OPT_c = 0x1,
+ OPT_d = 0x2,
+ OPT_u = 0x4,
+ OPT_f = 0x8,
+ OPT_s = 0x10,
+ OPT_w = 0x20,
+ };
skip_fields = skip_chars = 0;
+ max_chars = INT_MAX;
- while ((opt = getopt(argc, argv, uniq_opts)) > 0) {
- if (opt == 'f') {
- skip_fields = bb_xgetularg10(optarg);
- } else if (opt == 's') {
- skip_chars = bb_xgetularg10(optarg);
- } else if ((s0 = strchr(uniq_opts, opt)) != NULL) {
- uniq_flags &= s0[4];
- uniq_flags |= s0[7];
- } else {
- bb_show_usage();
- }
- }
+ opt_complementary = "f+:s+:w+";
+ opt = getopt32(argv, "cduf:s:w:", &skip_fields, &skip_chars, &max_chars);
+ argv += optind;
- input_filename = *(argv += optind);
+ input_filename = *argv;
- in = xgetoptfile_sort_uniq(argv, "r");
+ in = xgetoptfile_uniq_s(argv, 0);
if (*argv) {
++argv;
}
- out = xgetoptfile_sort_uniq(argv, "w");
+ out = xgetoptfile_uniq_s(argv, 2);
if (*argv && argv[1]) {
bb_show_usage();
}
- s0 = NULL;
+ s1 = e1 = NULL; /* prime the pump */
+
+ do {
+ s0 = s1;
+ e0 = e1;
+ dups = 0;
- /* gnu uniq ignores newlines */
- while ((s1 = bb_get_chomped_line_from_file(in)) != NULL) {
- e1 = s1;
- for (i=skip_fields ; i ; i--) {
- e1 = bb_skip_whitespace(e1);
- while (*e1 && !isspace(*e1)) {
+ /* gnu uniq ignores newlines */
+ while ((s1 = xmalloc_fgetline(in)) != NULL) {
+ e1 = s1;
+ for (i = skip_fields; i; i--) {
+ e1 = skip_whitespace(e1);
+ e1 = skip_non_whitespace(e1);
+ }
+ for (i = skip_chars; *e1 && i; i--) {
++e1;
}
+
+ if (!s0 || strncmp(e0, e1, max_chars)) {
+ break;
+ }
+
+ ++dups; /* note: testing for overflow seems excessive. */
}
- for (i = skip_chars ; *e1 && i ; i--) {
- ++e1;
- }
+
if (s0) {
- if (strcmp(e0, e1) == 0) {
- ++dups; /* Note: Testing for overflow seems excessive. */
- continue;
- }
- DO_LAST:
- if ((dups && (uniq_flags & 2)) || (!dups && (uniq_flags & 4))) {
- bb_fprintf(out, "\0%7d\t" + (uniq_flags & 1), dups + 1);
- bb_fprintf(out, "%s\n", s0);
+ if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_e) */
+ fprintf(out, "\0%ld " + (opt & 1), dups + 1); /* 1 == OPT_c */
+ fprintf(out, "%s\n", s0);
}
free((void *)s0);
}
+ } while (s1);
- s0 = s1;
- e0 = e1;
- dups = 0;
- }
-
- if (s0) {
- e1 = NULL;
- goto DO_LAST;
- }
-
- bb_xferror(in, input_filename);
+ die_if_ferror(in, input_filename);
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
}
diff --git a/release/src/router/busybox/coreutils/usleep.c b/release/src/router/busybox/coreutils/usleep.c
index f570f273..e7acd5f8 100644
--- a/release/src/router/busybox/coreutils/usleep.c
+++ b/release/src/router/busybox/coreutils/usleep.c
@@ -4,36 +4,23 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */
-#include <stdlib.h>
-#include <limits.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int usleep_main(int argc, char **argv)
+int usleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int usleep_main(int argc UNUSED_PARAM, char **argv)
{
- if (argc != 2) {
+ if (!argv[1]) {
bb_show_usage();
}
- if (usleep(bb_xgetularg10_bnd(argv[1], 0, UINT_MAX))) {
+ if (usleep(xatou(argv[1]))) {
bb_perror_nomsg_and_die();
}
diff --git a/release/src/router/busybox/coreutils/uudecode.c b/release/src/router/busybox/coreutils/uudecode.c
index 4f9270c1..0298a4bd 100644
--- a/release/src/router/busybox/coreutils/uudecode.c
+++ b/release/src/router/busybox/coreutils/uudecode.c
@@ -1,353 +1,224 @@
-/* uudecode.c -- uudecode utility.
- * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright 2003, Glenn McGrath
*
- * This product is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*
- * This product 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.
+ * Based on specification from
+ * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html
*
- * You should have received a copy of the GNU General Public License
- * along with this product; see the file COPYING. If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
- *
- * Original copyright notice is retained at the end of this file.
+ * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the
+ * "end" line
*/
+#include "libbb.h"
-#include <stdio.h>
-#include <errno.h>
-#include <getopt.h>
-#include <string.h>
-#include <stdlib.h>
-#include "busybox.h"
-#include "pwd_.h"
-#include "grp_.h"
-
-/*struct passwd *getpwnam();*/
-
-/* Single character decode. */
-#define DEC(Char) (((Char) - ' ') & 077)
-
-static int read_stduu (const char *inname)
+static void read_stduu(FILE *src_stream, FILE *dst_stream)
{
- char buf[2 * BUFSIZ];
-
- while (1) {
- int n;
- char *p;
-
- if (fgets (buf, sizeof(buf), stdin) == NULL) {
- bb_error_msg("%s: Short file", inname);
- return FALSE;
- }
- p = buf;
-
- /* N is used to avoid writing out all the characters at the end of
- the file. */
- n = DEC (*p);
- if (n <= 0)
- break;
- for (++p; n > 0; p += 4, n -= 3) {
- char ch;
-
- if (n >= 3) {
- ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
- putchar (ch);
- ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
- putchar (ch);
- ch = DEC (p[2]) << 6 | DEC (p[3]);
- putchar (ch);
- } else {
- if (n >= 1) {
- ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
- putchar (ch);
- }
- if (n >= 2) {
- ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
- putchar (ch);
- }
- }
- }
- }
-
- if (fgets (buf, sizeof(buf), stdin) == NULL
- || strcmp (buf, "end\n")) {
- bb_error_msg("%s: No `end' line", inname);
- return FALSE;
- }
-
- return TRUE;
+ char *line;
+
+ while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+ int encoded_len, str_len;
+ char *line_ptr, *dst;
+
+ if (strcmp(line, "end") == 0) {
+ return; /* the only non-error exit */
+ }
+
+ line_ptr = line;
+ while (*line_ptr) {
+ *line_ptr = (*line_ptr - 0x20) & 0x3f;
+ line_ptr++;
+ }
+ str_len = line_ptr - line;
+
+ encoded_len = line[0] * 4 / 3;
+ /* Check that line is not too short. (we tolerate
+ * overly _long_ line to accomodate possible extra '`').
+ * Empty line case is also caught here. */
+ if (str_len <= encoded_len) {
+ break; /* go to bb_error_msg_and_die("short file"); */
+ }
+ if (encoded_len <= 0) {
+ /* Ignore the "`\n" line, why is it even in the encode file ? */
+ free(line);
+ continue;
+ }
+ if (encoded_len > 60) {
+ bb_error_msg_and_die("line too long");
+ }
+
+ dst = line;
+ line_ptr = line + 1;
+ do {
+ /* Merge four 6 bit chars to three 8 bit chars */
+ *dst++ = line_ptr[0] << 2 | line_ptr[1] >> 4;
+ encoded_len--;
+ if (encoded_len == 0) {
+ break;
+ }
+
+ *dst++ = line_ptr[1] << 4 | line_ptr[2] >> 2;
+ encoded_len--;
+ if (encoded_len == 0) {
+ break;
+ }
+
+ *dst++ = line_ptr[2] << 6 | line_ptr[3];
+ line_ptr += 4;
+ encoded_len -= 2;
+ } while (encoded_len > 0);
+ fwrite(line, 1, dst - line, dst_stream);
+ free(line);
+ }
+ bb_error_msg_and_die("short file");
}
-static int read_base64 (const char *inname)
+static void read_base64(FILE *src_stream, FILE *dst_stream)
{
- static const char b64_tab[256] = {
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
- '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/
- '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/
- '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
- '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/
- '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/
- '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/
- '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/
- '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/
- '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/
- '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/
- '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
- '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
- };
- unsigned char buf[2 * BUFSIZ];
-
- while (1) {
- int last_data = 0;
- unsigned char *p;
-
- if (fgets (buf, sizeof(buf), stdin) == NULL) {
- bb_error_msg("%s: Short file", inname);
- return FALSE;
- }
- p = buf;
-
- if (memcmp (buf, "====", 4) == 0)
- break;
- if (last_data != 0) {
- bb_error_msg("%s: data following `=' padding character", inname);
- return FALSE;
- }
-
- /* The following implementation of the base64 decoding might look
- a bit clumsy but I only try to follow the POSIX standard:
- ``All line breaks or other characters not found in the table
- [with base64 characters] shall be ignored by decoding
- software.'' */
- while (*p != '\n') {
- char c1, c2, c3;
-
- while ((b64_tab[*p] & '\100') != 0)
- if (*p == '\n' || *p++ == '=')
- break;
- if (*p == '\n')
- /* This leaves the loop. */
- continue;
- c1 = b64_tab[*p++];
-
- while ((b64_tab[*p] & '\100') != 0)
- if (*p == '\n' || *p++ == '=') {
- bb_error_msg("%s: illegal line", inname);
- return FALSE;
- }
- c2 = b64_tab[*p++];
-
- while (b64_tab[*p] == '\177')
- if (*p++ == '\n') {
- bb_error_msg("%s: illegal line", inname);
- return FALSE;
- }
- if (*p == '=') {
- putchar (c1 << 2 | c2 >> 4);
- last_data = 1;
- break;
- }
- c3 = b64_tab[*p++];
-
- while (b64_tab[*p] == '\177')
- if (*p++ == '\n') {
- bb_error_msg("%s: illegal line", inname);
- return FALSE;
- }
- putchar (c1 << 2 | c2 >> 4);
- putchar (c2 << 4 | c3 >> 2);
- if (*p == '=') {
- last_data = 1;
- break;
- }
- else
- putchar (c3 << 6 | b64_tab[*p++]);
- }
- }
-
- return TRUE;
+ int term_count = 1;
+
+ while (1) {
+ char translated[4];
+ int count = 0;
+
+ while (count < 4) {
+ char *table_ptr;
+ int ch;
+
+ /* Get next _valid_ character.
+ * global vector bb_uuenc_tbl_base64[] contains this string:
+ * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n"
+ */
+ do {
+ ch = fgetc(src_stream);
+ if (ch == EOF) {
+ bb_error_msg_and_die("short file");
+ }
+ table_ptr = strchr(bb_uuenc_tbl_base64, ch);
+ } while (table_ptr == NULL);
+
+ /* Convert encoded character to decimal */
+ ch = table_ptr - bb_uuenc_tbl_base64;
+
+ if (*table_ptr == '=') {
+ if (term_count == 0) {
+ translated[count] = '\0';
+ break;
+ }
+ term_count++;
+ } else if (*table_ptr == '\n') {
+ /* Check for terminating line */
+ if (term_count == 5) {
+ return;
+ }
+ term_count = 1;
+ continue;
+ } else {
+ translated[count] = ch;
+ count++;
+ term_count = 0;
+ }
+ }
+
+ /* Merge 6 bit chars to 8 bit */
+ if (count > 1) {
+ fputc(translated[0] << 2 | translated[1] >> 4, dst_stream);
+ }
+ if (count > 2) {
+ fputc(translated[1] << 4 | translated[2] >> 2, dst_stream);
+ }
+ if (count > 3) {
+ fputc(translated[2] << 6 | translated[3], dst_stream);
+ }
+ }
}
-static int decode (const char *inname,
- const char *forced_outname)
+int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int uudecode_main(int argc UNUSED_PARAM, char **argv)
{
- struct passwd *pw;
- register char *p;
- int mode;
- char buf[2 * BUFSIZ];
- char *outname;
- int do_base64 = 0;
- int res;
- int dofre;
-
- /* Search for header line. */
-
- while (1) {
- if (fgets (buf, sizeof (buf), stdin) == NULL) {
- bb_error_msg("%s: No `begin' line", inname);
- return FALSE;
- }
-
- if (strncmp (buf, "begin", 5) == 0) {
- if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
- do_base64 = 1;
- break;
- } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
- break;
- }
- }
-
- /* If the output file name is given on the command line this rules. */
- dofre = FALSE;
- if (forced_outname != NULL)
- outname = (char *) forced_outname;
- else {
- /* Handle ~user/file format. */
- if (buf[0] != '~')
- outname = buf;
- else {
- p = buf + 1;
- while (*p != '/')
- ++p;
- if (*p == '\0') {
- bb_error_msg("%s: Illegal ~user", inname);
- return FALSE;
- }
- *p++ = '\0';
- pw = getpwnam (buf + 1);
- if (pw == NULL) {
- bb_error_msg("%s: No user `%s'", inname, buf + 1);
- return FALSE;
- }
- outname = concat_path_file(pw->pw_dir, p);
- dofre = TRUE;
- }
- }
-
- /* Create output file and set mode. */
- if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
- && (freopen (outname, "w", stdout) == NULL
- || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
- )) {
- bb_perror_msg("%s", outname); /* */
- if (dofre)
- free(outname);
- return FALSE;
- }
-
- /* We differenciate decoding standard UU encoding and base64. A
- common function would only slow down the program. */
-
- /* For each input line: */
- if (do_base64)
- res = read_base64 (inname);
- else
- res = read_stduu (inname);
- if (dofre)
- free(outname);
- return res;
-}
-
-int uudecode_main (int argc,
- char **argv)
-{
- int opt;
- int exit_status;
- const char *outname;
- outname = NULL;
-
- while ((opt = getopt(argc, argv, "o:")) != EOF) {
- switch (opt) {
- case 0:
- break;
-
- case 'o':
- outname = optarg;
- break;
-
- default:
- bb_show_usage();
- }
- }
-
- if (optind == argc)
- exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
- else {
- exit_status = EXIT_SUCCESS;
- do {
- if (freopen (argv[optind], "r", stdin) != NULL) {
- if (decode (argv[optind], outname) != 0)
- exit_status = FALSE;
- } else {
- bb_perror_msg("%s", argv[optind]);
- exit_status = EXIT_FAILURE;
- }
- optind++;
- }
- while (optind < argc);
- }
- return(exit_status);
+ FILE *src_stream;
+ char *outname = NULL;
+ char *line;
+
+ opt_complementary = "?1"; /* 1 argument max */
+ getopt32(argv, "o:", &outname);
+ argv += optind;
+
+ if (!*argv)
+ *--argv = (char*)"-";
+ src_stream = xfopen_stdin(*argv);
+
+ /* Search for the start of the encoding */
+ while ((line = xmalloc_fgetline(src_stream)) != NULL) {
+ void (*decode_fn_ptr)(FILE *src, FILE *dst);
+ char *line_ptr;
+ FILE *dst_stream;
+ int mode;
+
+ if (strncmp(line, "begin-base64 ", 13) == 0) {
+ line_ptr = line + 13;
+ decode_fn_ptr = read_base64;
+ } else if (strncmp(line, "begin ", 6) == 0) {
+ line_ptr = line + 6;
+ decode_fn_ptr = read_stduu;
+ } else {
+ free(line);
+ continue;
+ }
+
+ /* begin line found. decode and exit */
+ mode = bb_strtou(line_ptr, NULL, 8);
+ if (outname == NULL) {
+ outname = strchr(line_ptr, ' ');
+ if ((outname == NULL) || (*outname == '\0')) {
+ break;
+ }
+ outname++;
+ }
+ dst_stream = stdout;
+ if (NOT_LONE_DASH(outname)) {
+ dst_stream = xfopen_for_write(outname);
+ fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ }
+ free(line);
+ decode_fn_ptr(src_stream, dst_stream);
+ /* fclose_if_not_stdin(src_stream); - redundant */
+ return EXIT_SUCCESS;
+ }
+ bb_error_msg_and_die("no 'begin' line");
}
-/* Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
- * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
- *
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-
+/* Test script.
+Put this into an empty dir with busybox binary, an run.
+
+#!/bin/sh
+test -x busybox || { echo "No ./busybox?"; exit; }
+ln -sf busybox uudecode
+ln -sf busybox uuencode
+>A_null
+echo -n A >A
+echo -n AB >AB
+echo -n ABC >ABC
+echo -n ABCD >ABCD
+echo -n ABCDE >ABCDE
+echo -n ABCDEF >ABCDEF
+cat busybox >A_bbox
+for f in A*; do
+ echo uuencode $f
+ ./uuencode $f <$f >u_$f
+ ./uuencode -m $f <$f >m_$f
+done
+mkdir unpk_u unpk_m 2>/dev/null
+for f in u_*; do
+ ./uudecode <$f -o unpk_u/${f:2}
+ diff -a ${f:2} unpk_u/${f:2} >/dev/null 2>&1
+ echo uudecode $f: $?
+done
+for f in m_*; do
+ ./uudecode <$f -o unpk_m/${f:2}
+ diff -a ${f:2} unpk_m/${f:2} >/dev/null 2>&1
+ echo uudecode $f: $?
+done
+*/
diff --git a/release/src/router/busybox/coreutils/uuencode.c b/release/src/router/busybox/coreutils/uuencode.c
index fd3326d8..e19f9967 100644
--- a/release/src/router/busybox/coreutils/uuencode.c
+++ b/release/src/router/busybox/coreutils/uuencode.c
@@ -5,145 +5,57 @@
* based on the function base64_encode from http.c in wget v1.6
* Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include "busybox.h"
-/* Conversion table. for base 64 */
-static const char tbl_base64[65] = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z', '0', '1', '2', '3',
- '4', '5', '6', '7', '8', '9', '+', '/',
- '=' /* termination character */
-};
+#include "libbb.h"
-static const char tbl_std[65] = {
- '`', '!', '"', '#', '$', '%', '&', '\'',
- '(', ')', '*', '+', ',', '-', '.', '/',
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', ':', ';', '<', '=', '>', '?',
- '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
- 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
- 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
- '`' /* termination character */
+enum {
+ SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */
+ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
};
-/*
- * Encode the string S of length LENGTH to base64 format and place it
- * to STORE. STORE will be 0-terminated, and must point to a writable
- * buffer of at least 1+BASE64_LENGTH(length) bytes.
- * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))
- */
-static void uuencode (const char *s, const char *store, const int length, const char *tbl)
-{
- int i;
- unsigned char *p = (unsigned char *)store;
-
- /* Transform the 3x8 bits to 4x6 bits, as required by base64. */
- for (i = 0; i < length; i += 3) {
- *p++ = tbl[s[0] >> 2];
- *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
- *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
- *p++ = tbl[s[2] & 0x3f];
- s += 3;
- }
- /* Pad the result if necessary... */
- if (i == length + 1) {
- *(p - 1) = tbl[64];
- }
- else if (i == length + 2) {
- *(p - 1) = *(p - 2) = tbl[64];
- }
- /* ...and zero-terminate it. */
- *p = '\0';
-}
-
-#define SRC_BUF_SIZE 45 // This *MUST* be a multiple of 3
-#define DST_BUF_SIZE 4 * ((SRC_BUF_SIZE + 2) / 3)
+int uuencode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int uuencode_main(int argc, char **argv)
{
- const int src_buf_size = SRC_BUF_SIZE;
- const int dst_buf_size = DST_BUF_SIZE;
- int write_size = dst_buf_size;
struct stat stat_buf;
- FILE *src_stream = stdin;
+ int src_fd = STDIN_FILENO;
const char *tbl;
- size_t size;
mode_t mode;
- RESERVE_CONFIG_BUFFER(src_buf, SRC_BUF_SIZE + 1);
- RESERVE_CONFIG_BUFFER(dst_buf, DST_BUF_SIZE + 1);
-
- tbl = tbl_std;
- if (bb_getopt_ulflags(argc, argv, "m") & 1) {
- tbl = tbl_base64;
+ char src_buf[SRC_BUF_SIZE];
+ char dst_buf[DST_BUF_SIZE + 1];
+
+ tbl = bb_uuenc_tbl_std;
+ mode = 0666 & ~umask(0666);
+ opt_complementary = "-1:?2"; /* must have 1 or 2 args */
+ if (getopt32(argv, "m")) {
+ tbl = bb_uuenc_tbl_base64;
}
-
- switch (argc - optind) {
- case 2:
- src_stream = bb_xfopen(argv[optind], "r");
- if (stat(argv[optind], &stat_buf) < 0) {
- bb_perror_msg_and_die("stat");
- }
- mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- if (src_stream == stdout) {
- puts("NULL");
- }
- break;
- case 1:
- mode = 0666 & ~umask(0666);
- break;
- default:
- bb_show_usage();
+ argv += optind;
+ if (argc == optind + 2) {
+ src_fd = xopen(*argv, O_RDONLY);
+ fstat(src_fd, &stat_buf);
+ mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ argv++;
}
- bb_printf("begin%s %o %s", tbl == tbl_std ? "" : "-base64", mode, argv[argc - 1]);
-
- while ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0) {
- if (size != src_buf_size) {
- /* write_size is always 60 until the last line */
- write_size=(4 * ((size + 2) / 3));
- /* pad with 0s so we can just encode extra bits */
- memset(&src_buf[size], 0, src_buf_size - size);
- }
+ printf("begin%s %o %s", tbl == bb_uuenc_tbl_std ? "" : "-base64", mode, *argv);
+ while (1) {
+ size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE);
+ if (!size)
+ break;
+ if ((ssize_t)size < 0)
+ bb_perror_msg_and_die(bb_msg_read_error);
/* Encode the buffer we just read in */
- uuencode(src_buf, dst_buf, size, tbl);
-
- putchar('\n');
- if (tbl == tbl_std) {
- putchar(tbl[size]);
- }
- if (fwrite(dst_buf, 1, write_size, stdout) != write_size) {
- bb_perror_msg_and_die(bb_msg_write_error);
+ bb_uuencode(dst_buf, src_buf, size, tbl);
+ bb_putchar('\n');
+ if (tbl == bb_uuenc_tbl_std) {
+ bb_putchar(tbl[size]);
}
+ fflush(stdout);
+ xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3));
}
- bb_printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n");
-
- bb_xferror(src_stream, "source"); /* TODO - Fix this! */
+ printf(tbl == bb_uuenc_tbl_std ? "\n`\nend\n" : "\n====\n");
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
+ fflush_stdout_and_exit(EXIT_SUCCESS);
}
diff --git a/release/src/router/busybox/coreutils/watch.c b/release/src/router/busybox/coreutils/watch.c
deleted file mode 100644
index f9f40189..00000000
--- a/release/src/router/busybox/coreutils/watch.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/* vi: set sw=4 ts=4: */
-/*
- * Mini watch implementation for busybox
- *
- * Copyright (C) 2001 by Michael Habermann <mhabermann@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-/* BB_AUDIT SUSv3 N/A */
-/* BB_AUDIT GNU defects -- only option -n is supported. */
-
-/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
- *
- * Removed dependency on date_main(), added proper error checking, and
- * reduced size.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <time.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include "busybox.h"
-
-extern int watch_main(int argc, char **argv)
-{
- const int header_len = 40;
- time_t t;
- pid_t pid;
- unsigned period = 2;
- int old_stdout;
- int len, len2;
- char **watched_argv;
- char header[header_len + 1];
-
- if (argc < 2) {
- bb_show_usage();
- }
-
- /* don't use getopt, because it permutes the arguments */
- ++argv;
- if ((argc > 3) && !strcmp(*argv, "-n")
- ) {
- period = bb_xgetularg10_bnd(argv[1], 1, UINT_MAX);
- argv += 2;
- }
- watched_argv = argv;
-
- /* create header */
-
- len = snprintf(header, header_len, "Every %ds:", period);
- /* Don't bother checking for len < 0, as it should never happen.
- * But, just to be prepared... */
- assert(len >= 0);
- do {
- len2 = strlen(*argv);
- if (len + len2 >= header_len-1) {
- break;
- }
- header[len] = ' ';
- memcpy(header+len+1, *argv, len2);
- len += len2+1;
- } while (*++argv);
-
- header[len] = 0;
-
- /* thanks to lye, who showed me how to redirect stdin/stdout */
- old_stdout = dup(1);
-
- while (1) {
- time(&t);
- /* Use dprintf to avoid fflush()ing stdout. */
- if (dprintf(1, "\033[H\033[J%-*s%s\n", header_len, header, ctime(&t)) < 0) {
- bb_perror_msg_and_die("printf");
- }
-
- pid = vfork(); /* vfork, because of ucLinux */
- if (pid > 0) {
- //parent
- wait(0);
- sleep(period);
- } else if (0 == pid) {
- //child
- close(1);
- dup(old_stdout);
- if (execvp(*watched_argv, watched_argv)) {
- bb_error_msg_and_die("Couldn't run command\n");
- }
- } else {
- bb_error_msg_and_die("Couldn't vfork\n");
- }
- }
-}
diff --git a/release/src/router/busybox/coreutils/wc.c b/release/src/router/busybox/coreutils/wc.c
index 77990152..d0e5482c 100644
--- a/release/src/router/busybox/coreutils/wc.c
+++ b/release/src/router/busybox/coreutils/wc.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 _NOT_ compliant -- option -m is not currently supported. */
@@ -26,7 +13,7 @@
/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
*
* Rewritten to fix a number of problems and do some size optimizations.
- * Problems in the previous busybox implementation (besides bloat) included:
+ * Problems in the previous busybox implementation (besides bloat) included:
* 1) broken 'wc -c' optimization (read note below)
* 2) broken handling of '-' args
* 3) no checking of ferror on EOF returns
@@ -49,20 +36,14 @@
* (adapted from example in gnu wc.c)
*
* echo hello > /tmp/testfile &&
- * (dd ibs=1k skip=1 count=0 &> /dev/null ; wc -c) < /tmp/testfile
+ * (dd ibs=1k skip=1 count=0 &> /dev/null; wc -c) < /tmp/testfile
*
* for which 'wc -c' should output '0'.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-#ifdef CONFIG_LOCALE_SUPPORT
-#include <locale.h>
-#include <ctype.h>
+#if ENABLE_LOCALE_SUPPORT
#define isspace_given_isprint(c) isspace(c)
#else
#undef isspace
@@ -72,6 +53,14 @@
#define isspace_given_isprint(c) ((c) == ' ')
#endif
+#if ENABLE_FEATURE_WC_LARGE
+#define COUNT_T unsigned long long
+#define COUNT_FMT "llu"
+#else
+#define COUNT_T unsigned
+#define COUNT_FMT "u"
+#endif
+
enum {
WC_LINES = 0,
WC_WORDS = 1,
@@ -79,65 +68,57 @@ enum {
WC_LENGTH = 3
};
-/* Note: If this changes, remember to change the initialization of
- * 'name' in wc_main. It needs to point to the terminating nul. */
-static const char wc_opts[] = "lwcL"; /* READ THE WARNING ABOVE! */
-
-enum {
- OP_INC_LINE = 1, /* OP_INC_LINE must be 1. */
- OP_SPACE = 2,
- OP_NEWLINE = 4,
- OP_TAB = 8,
- OP_NUL = 16,
-};
-
-/* Note: If fmt_str changes, the offsets to 's' in the OUTPUT section
- * will need to be updated. */
-static const char fmt_str[] = " %7u\0 %s\n";
-static const char total_str[] = "total";
-
-int wc_main(int argc, char **argv)
+int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int wc_main(int argc UNUSED_PARAM, char **argv)
{
FILE *fp;
- const char *s;
- unsigned int *pcounts;
- unsigned int counts[4];
- unsigned int totals[4];
- unsigned int linepos;
- unsigned int u;
+ const char *s, *arg;
+ const char *start_fmt = " %9"COUNT_FMT + 1;
+ const char *fname_fmt = " %s\n";
+ COUNT_T *pcounts;
+ COUNT_T counts[4];
+ COUNT_T totals[4];
+ unsigned linepos;
+ unsigned u;
int num_files = 0;
int c;
- char status = EXIT_SUCCESS;
- char in_word;
- char print_type;
-
- print_type = bb_getopt_ulflags(argc, argv, wc_opts);
-
+ smallint status = EXIT_SUCCESS;
+ smallint in_word;
+ unsigned print_type;
+
+ print_type = getopt32(argv, "lwcL");
+
if (print_type == 0) {
print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS);
}
-
+
argv += optind;
- if (!*argv) {
+ if (!argv[0]) {
*--argv = (char *) bb_msg_standard_input;
+ fname_fmt = "\n";
+ if (!((print_type-1) & print_type)) /* exactly one option? */
+ start_fmt = "%"COUNT_FMT;
}
-
+
memset(totals, 0, sizeof(totals));
-
+
pcounts = counts;
-
- do {
+
+ while ((arg = *argv++) != 0) {
++num_files;
- if (!(fp = bb_wfopen_input(*argv))) {
+ fp = fopen_or_warn_stdin(arg);
+ if (!fp) {
status = EXIT_FAILURE;
continue;
}
-
+
memset(counts, 0, sizeof(counts));
linepos = 0;
in_word = 0;
-
+
do {
+ /* Our -w doesn't match GNU wc exactly... oh well */
+
++counts[WC_CHARS];
c = getc(fp);
if (isprint(c)) {
@@ -169,7 +150,7 @@ int wc_main(int argc, char **argv)
}
} else if (c == EOF) {
if (ferror(fp)) {
- bb_perror_msg("%s", *argv);
+ bb_simple_perror_msg(arg);
status = EXIT_FAILURE;
}
--counts[WC_CHARS];
@@ -177,51 +158,48 @@ int wc_main(int argc, char **argv)
} else {
continue;
}
-
+
counts[WC_WORDS] += in_word;
in_word = 0;
if (c == EOF) {
break;
}
} while (1);
-
+
if (totals[WC_LENGTH] < counts[WC_LENGTH]) {
totals[WC_LENGTH] = counts[WC_LENGTH];
}
totals[WC_LENGTH] -= counts[WC_LENGTH];
-
- bb_fclose_nonstdin(fp);
-
+
+ fclose_if_not_stdin(fp);
+
OUTPUT:
- s = fmt_str + 1; /* Skip the leading space on 1st pass. */
+ /* coreutils wc tries hard to print pretty columns
+ * (saves results for all files, find max col len etc...)
+ * we won't try that hard, it will bloat us too much */
+ s = start_fmt;
u = 0;
do {
if (print_type & (1 << u)) {
- bb_printf(s, pcounts[u]);
- s = fmt_str; /* Ok... restore the leading space. */
+ printf(s, pcounts[u]);
+ s = " %9"COUNT_FMT; /* Ok... restore the leading space. */
}
totals[u] += pcounts[u];
} while (++u < 4);
-
- s += 8; /* Set the format to the empty string. */
-
- if (*argv != bb_msg_standard_input) {
- s -= 3; /* We have a name, so do %s conversion. */
- }
- bb_printf(s, *argv);
-
- } while (*++argv);
-
+ printf(fname_fmt, arg);
+ }
+
/* If more than one file was processed, we want the totals. To save some
* space, we set the pcounts ptr to the totals array. This has the side
* effect of trashing the totals array after outputting it, but that's
* irrelavent since we no longer need it. */
if (num_files > 1) {
num_files = 0; /* Make sure we don't get here again. */
- *--argv = (char *) total_str;
+ arg = "total";
pcounts = totals;
+ --argv;
goto OUTPUT;
}
-
- bb_fflush_stdout_and_exit(status);
+
+ fflush_stdout_and_exit(status);
}
diff --git a/release/src/router/busybox/coreutils/who.c b/release/src/router/busybox/coreutils/who.c
index 1bf55205..85a0025c 100644
--- a/release/src/router/busybox/coreutils/who.c
+++ b/release/src/router/busybox/coreutils/who.c
@@ -1,6 +1,6 @@
/* vi: set sw=4 ts=4: */
/*----------------------------------------------------------------------
- * Mini who is used to display user name, login time,
+ * Mini who is used to display user name, login time,
* idle time and host name.
*
* Author: Da Chen <dchen@ayrnetworks.com>
@@ -10,74 +10,70 @@
* as published by the Free Software Foundation:
* http://www.gnu.org/copyleft/gpl.html
*
- * Copyright (c) 2002 AYR Networks, Inc.
+ * Copyright (c) 2002 AYR Networks, Inc.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ *
*----------------------------------------------------------------------
*/
+/* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -H, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include "libbb.h"
#include <utmp.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include "busybox.h"
-extern int who_main(int argc, char **argv)
+static void idle_string(char *str6, time_t t)
{
- struct utmp *ut;
- struct stat st;
- int devlen, len;
- time_t now, idle;
-
- if (argc > 1)
- bb_show_usage();
+ t = time(NULL) - t;
- setutent();
- devlen = sizeof("/dev/") - 1;
- printf("USER TTY IDLE FROM HOST\n");
-
- while ((ut = getutent()) != NULL) {
- char name[40];
+ /*if (t < 60) {
+ str6[0] = '.';
+ str6[1] = '\0';
+ return;
+ }*/
+ if (t >= 0 && t < (24 * 60 * 60)) {
+ sprintf(str6, "%02d:%02d",
+ (int) (t / (60 * 60)),
+ (int) ((t % (60 * 60)) / 60));
+ return;
+ }
+ strcpy(str6, "old");
+}
- if (ut->ut_user[0] && ut->ut_type == USER_PROCESS) {
- len = strlen(ut->ut_line);
- if (ut->ut_line[0] == '/') {
- strncpy(name, ut->ut_line, len);
- name[len] = '\0';
- strcpy(ut->ut_line, ut->ut_line + devlen);
- } else {
- strcpy(name, "/dev/");
- strncpy(name+devlen, ut->ut_line, len);
- name[devlen+len] = '\0';
- }
-
- printf("%-10s %-8s ", ut->ut_user, ut->ut_line);
+int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int who_main(int argc UNUSED_PARAM, char **argv)
+{
+ char str6[6];
+ struct utmp *ut;
+ struct stat st;
+ char *name;
+ unsigned opt;
- if (stat(name, &st) == 0) {
- now = time(NULL);
- idle = now - st.st_atime;
-
- if (idle < 60)
- printf("00:00m ");
- else if (idle < (60 * 60))
- printf("00:%02dm ", (int)(idle / 60));
- else if (idle < (24 * 60 * 60))
- printf("%02d:%02dm ", (int)(idle / (60 * 60)),
- (int)(idle % (60 * 60)) / 60);
- else if (idle < (24 * 60 * 60 * 365))
- printf("%03ddays ", (int)(idle / (24 * 60 * 60)));
- else
- printf("%02dyears ", (int) (idle / (24 * 60 * 60 * 365)));
- } else
- printf("%-8s ", "?");
-
- printf("%-12.12s %s\n", ctime(&(ut->ut_tv.tv_sec)) + 4, ut->ut_host);
- }
- }
- endutent();
+ opt_complementary = "=0";
+ opt = getopt32(argv, "a");
- return 0;
+ setutent();
+ printf("USER TTY IDLE TIME HOST\n");
+ while ((ut = getutent()) != NULL) {
+ if (ut->ut_user[0] && (opt || ut->ut_type == USER_PROCESS)) {
+ time_t tmp;
+ /* ut->ut_line is device name of tty - "/dev/" */
+ name = concat_path_file("/dev", ut->ut_line);
+ str6[0] = '?';
+ str6[1] = '\0';
+ if (stat(name, &st) == 0)
+ idle_string(str6, st.st_atime);
+ /* manpages say ut_tv.tv_sec *is* time_t,
+ * but some systems have it wrong */
+ tmp = ut->ut_tv.tv_sec;
+ /* 15 chars for time: Nov 10 19:33:20 */
+ printf("%-10s %-8s %-9s %-15.15s %s\n",
+ ut->ut_user, ut->ut_line, str6,
+ ctime(&tmp) + 4, ut->ut_host);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(name);
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP)
+ endutent();
+ return EXIT_SUCCESS;
}
diff --git a/release/src/router/busybox/coreutils/whoami.c b/release/src/router/busybox/coreutils/whoami.c
index f93034d3..0dbcba95 100644
--- a/release/src/router/busybox/coreutils/whoami.c
+++ b/release/src/router/busybox/coreutils/whoami.c
@@ -4,41 +4,23 @@
*
* Copyright (C) 2000 Edward Betts <edward@debian.org>.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "busybox.h"
+#include "libbb.h"
-extern int whoami_main(int argc, char **argv)
-{
- char user[9];
- uid_t uid;
+/* This is a NOFORK applet. Be very careful! */
+int whoami_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int whoami_main(int argc, char **argv UNUSED_PARAM)
+{
if (argc > 1)
bb_show_usage();
- uid = geteuid();
- if (my_getpwuid(user, uid)) {
- puts(user);
- bb_fflush_stdout_and_exit(EXIT_SUCCESS);
- }
- bb_error_msg_and_die("cannot find username for UID %u", (unsigned) uid);
+ /* Will complain and die if username not found */
+ puts(xuid2uname(geteuid()));
+
+ return fflush(stdout);
}
diff --git a/release/src/router/busybox/coreutils/yes.c b/release/src/router/busybox/coreutils/yes.c
index 74f7571c..9d3f6755 100644
--- a/release/src/router/busybox/coreutils/yes.c
+++ b/release/src/router/busybox/coreutils/yes.c
@@ -4,20 +4,7 @@
*
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */
@@ -27,29 +14,28 @@
* Size reductions and removed redundant applet name prefix from error messages.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include "busybox.h"
+#include "libbb.h"
+
+/* This is a NOFORK applet. Be very careful! */
-extern int yes_main(int argc, char **argv)
+int yes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int yes_main(int argc, char **argv)
{
- static const char fmt_str[] = " %s";
- const char *fmt;
- char **first_arg;
+ char **pp;
- *argv = "y";
+ argv[0] = (char*)"y";
if (argc != 1) {
++argv;
}
- first_arg = argv;
do {
- fmt = fmt_str + 1;
- do {
- bb_printf(fmt, *argv);
- fmt = fmt_str;
- } while (*++argv);
- argv = first_arg;
+ pp = argv;
+ while (1) {
+ fputs(*pp, stdout);
+ if (!*++pp)
+ break;
+ putchar(' ');
+ }
} while (putchar('\n') != EOF);
bb_perror_nomsg_and_die();