From 4aca87515a5083ae0e31ce3177189fd43b6d05ac Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 3 Jan 2015 13:58:15 +0100 Subject: patch to Vanilla Tomato 1.28 --- release/src/router/busybox/coreutils/Config.in | 669 +++++-- release/src/router/busybox/coreutils/Kbuild | 95 + release/src/router/busybox/coreutils/Makefile | 30 - release/src/router/busybox/coreutils/Makefile.in | 92 - release/src/router/busybox/coreutils/basename.c | 41 +- release/src/router/busybox/coreutils/cal.c | 201 +- release/src/router/busybox/coreutils/cat.c | 65 +- release/src/router/busybox/coreutils/catv.c | 75 + release/src/router/busybox/coreutils/chgrp.c | 84 +- release/src/router/busybox/coreutils/chmod.c | 200 +- release/src/router/busybox/coreutils/chown.c | 229 ++- release/src/router/busybox/coreutils/chroot.c | 36 +- release/src/router/busybox/coreutils/cksum.c | 67 + release/src/router/busybox/coreutils/cmp.c | 152 -- release/src/router/busybox/coreutils/comm.c | 100 + release/src/router/busybox/coreutils/cp.c | 167 +- release/src/router/busybox/coreutils/cut.c | 527 +++-- release/src/router/busybox/coreutils/date.c | 388 ++-- release/src/router/busybox/coreutils/dd.c | 438 ++-- release/src/router/busybox/coreutils/df.c | 224 ++- release/src/router/busybox/coreutils/dirname.c | 28 +- release/src/router/busybox/coreutils/dos2unix.c | 230 +-- release/src/router/busybox/coreutils/du.c | 261 ++- release/src/router/busybox/coreutils/echo.c | 268 ++- release/src/router/busybox/coreutils/env.c | 101 +- release/src/router/busybox/coreutils/expand.c | 180 ++ release/src/router/busybox/coreutils/expr.c | 656 +++--- release/src/router/busybox/coreutils/false.c | 27 +- release/src/router/busybox/coreutils/fold.c | 229 +-- release/src/router/busybox/coreutils/head.c | 120 +- release/src/router/busybox/coreutils/hostid.c | 28 +- release/src/router/busybox/coreutils/id.c | 270 ++- release/src/router/busybox/coreutils/id_test.sh | 244 +++ release/src/router/busybox/coreutils/install.c | 210 ++ release/src/router/busybox/coreutils/length.c | 21 +- .../router/busybox/coreutils/libcoreutils/Kbuild | 12 + .../router/busybox/coreutils/libcoreutils/Makefile | 30 - .../busybox/coreutils/libcoreutils/Makefile.in | 32 - .../busybox/coreutils/libcoreutils/coreutils.h | 18 +- .../busybox/coreutils/libcoreutils/cp_mv_stat.c | 17 +- .../coreutils/libcoreutils/getopt_mk_fifo_nod.c | 29 +- .../coreutils/libcoreutils/xgetoptfile_sort_uniq.c | 38 - release/src/router/busybox/coreutils/ln.c | 100 +- release/src/router/busybox/coreutils/logname.c | 36 +- release/src/router/busybox/coreutils/ls.c | 1348 ++++++------- .../src/router/busybox/coreutils/md5_sha1_sum.c | 192 ++ release/src/router/busybox/coreutils/md5sum.c | 1102 ---------- release/src/router/busybox/coreutils/mkdir.c | 69 +- release/src/router/busybox/coreutils/mkfifo.c | 30 +- release/src/router/busybox/coreutils/mknod.c | 64 +- release/src/router/busybox/coreutils/mv.c | 154 +- release/src/router/busybox/coreutils/nice.c | 55 + release/src/router/busybox/coreutils/nohup.c | 78 + release/src/router/busybox/coreutils/od.c | 98 +- release/src/router/busybox/coreutils/od_bloaty.c | 1428 +++++++++++++ release/src/router/busybox/coreutils/printenv.c | 37 + release/src/router/busybox/coreutils/printf.c | 656 +++--- release/src/router/busybox/coreutils/pwd.c | 30 +- release/src/router/busybox/coreutils/readlink.c | 72 + release/src/router/busybox/coreutils/realpath.c | 44 +- release/src/router/busybox/coreutils/rm.c | 50 +- release/src/router/busybox/coreutils/rmdir.c | 69 +- release/src/router/busybox/coreutils/seq.c | 53 + release/src/router/busybox/coreutils/sha1sum.c | 492 ----- release/src/router/busybox/coreutils/sleep.c | 106 +- release/src/router/busybox/coreutils/sort.c | 438 +++- release/src/router/busybox/coreutils/split.c | 139 ++ release/src/router/busybox/coreutils/stat.c | 669 +++++++ release/src/router/busybox/coreutils/stty.c | 2118 +++++++++++--------- release/src/router/busybox/coreutils/sum.c | 99 + release/src/router/busybox/coreutils/sync.c | 27 +- release/src/router/busybox/coreutils/tac.c | 106 + release/src/router/busybox/coreutils/tail.c | 311 ++- release/src/router/busybox/coreutils/tee.c | 135 +- release/src/router/busybox/coreutils/test.c | 968 +++++---- .../src/router/busybox/coreutils/test_ptr_hack.c | 23 + release/src/router/busybox/coreutils/touch.c | 91 +- release/src/router/busybox/coreutils/tr.c | 455 +++-- release/src/router/busybox/coreutils/true.c | 25 +- release/src/router/busybox/coreutils/tty.c | 46 +- release/src/router/busybox/coreutils/uname.c | 178 +- release/src/router/busybox/coreutils/uniq.c | 138 +- release/src/router/busybox/coreutils/usleep.c | 29 +- release/src/router/busybox/coreutils/uudecode.c | 545 ++--- release/src/router/busybox/coreutils/uuencode.c | 160 +- release/src/router/busybox/coreutils/watch.c | 110 - release/src/router/busybox/coreutils/wc.c | 148 +- release/src/router/busybox/coreutils/who.c | 118 +- release/src/router/busybox/coreutils/whoami.c | 38 +- release/src/router/busybox/coreutils/yes.c | 44 +- 90 files changed, 11451 insertions(+), 8999 deletions(-) mode change 100755 => 100644 release/src/router/busybox/coreutils/Config.in create mode 100644 release/src/router/busybox/coreutils/Kbuild delete mode 100644 release/src/router/busybox/coreutils/Makefile delete mode 100755 release/src/router/busybox/coreutils/Makefile.in create mode 100644 release/src/router/busybox/coreutils/catv.c create mode 100644 release/src/router/busybox/coreutils/cksum.c delete mode 100644 release/src/router/busybox/coreutils/cmp.c create mode 100644 release/src/router/busybox/coreutils/comm.c create mode 100644 release/src/router/busybox/coreutils/expand.c create mode 100755 release/src/router/busybox/coreutils/id_test.sh create mode 100644 release/src/router/busybox/coreutils/install.c create mode 100644 release/src/router/busybox/coreutils/libcoreutils/Kbuild delete mode 100644 release/src/router/busybox/coreutils/libcoreutils/Makefile delete mode 100755 release/src/router/busybox/coreutils/libcoreutils/Makefile.in delete mode 100644 release/src/router/busybox/coreutils/libcoreutils/xgetoptfile_sort_uniq.c create mode 100644 release/src/router/busybox/coreutils/md5_sha1_sum.c delete mode 100644 release/src/router/busybox/coreutils/md5sum.c create mode 100644 release/src/router/busybox/coreutils/nice.c create mode 100644 release/src/router/busybox/coreutils/nohup.c create mode 100644 release/src/router/busybox/coreutils/od_bloaty.c create mode 100644 release/src/router/busybox/coreutils/printenv.c create mode 100644 release/src/router/busybox/coreutils/readlink.c create mode 100644 release/src/router/busybox/coreutils/seq.c delete mode 100644 release/src/router/busybox/coreutils/sha1sum.c create mode 100644 release/src/router/busybox/coreutils/split.c create mode 100644 release/src/router/busybox/coreutils/stat.c create mode 100644 release/src/router/busybox/coreutils/sum.c create mode 100644 release/src/router/busybox/coreutils/tac.c create mode 100644 release/src/router/busybox/coreutils/test_ptr_hack.c delete mode 100644 release/src/router/busybox/coreutils/watch.c (limited to 'release/src/router/busybox/coreutils') diff --git a/release/src/router/busybox/coreutils/Config.in b/release/src/router/busybox/coreutils/Config.in old mode 100755 new mode 100644 index 3f1e714e..b047ce5e --- 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 +# +# 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 -# -# 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 -# -# 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 + * Copyright (C) 1999-2004 by 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 + * 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 -#include -#include -#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 - * * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" +#include "libbb.h" -#ifdef CONFIG_LOCALE_SUPPORT -#include -#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 * - * 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 -#include -#include -#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 + * + * 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 - * - * 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 * + * 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 -#include -#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 + * Copyright (C) 1999-2004 by Erik Andersen * * Reworked by (C) 2002 Vladimir Oleynik * 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 -#include -#include -#include -#include -#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 - * - * 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 * + * 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 -#include -#include -#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(¶m.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 */ + ¶m, /* 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 - * - * 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 * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ -#include -#include -#include -#include -#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 - * - * 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 -#include -#include -#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 + * + * 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 + * SELinux support by Yuichi Nakamura * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 , - * - * 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 + * debloated by Bernhard Reutner-Fischer * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include -#include -#include -#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(<ok, "-"); - 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(<ok, "-"); - 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, <ok); +// 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(<ok, "-"); + 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 - * - * iso-format handling added by Robert Griebl - * - * 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 + * bugfixes and cleanup by Bernhard Reutner-Fischer * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ -#include -#include -#include -#include -#include -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#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 + * Copyright (C) 1999-2004 by Erik Andersen * based on original code by (I think) Bruce Perens . * - * 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 -#include -#include -#include #include #include -#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 - * - * 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 * + * 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 -#include -#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 . * 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 -#include -#include -#include -#include -#include -#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 * Copyright (C) 2002 Edward Betts * - * 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 -#include -#include -#include -#include -#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 -#include -#include -#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. + * 3. * * 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 (C) 2003 - * - corretion "-" option usage + * Modified by Vladimir Oleynik (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 -#include -#include -#include -#include -#include -#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 + * + * 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 + * + * 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 . + * Copyright (C) 2003-2005 Vladimir Oleynik + * - 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 -#include -#include -#include -#include -#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 - * - * 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 * + * 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 -#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 + 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 -#include -#include -#include -#include -#include -#include - -#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 * - * 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 -#include -#include -#include -#include -#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 . * - * 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 -#include -#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 + * Copyright (C) 2008 by Tito Ragusa * - * 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 + * Added -G option Tito Ragusa (C) 2008 for SUSv3. + */ -#include "busybox.h" -#include -#include -#include -#include -#include -#ifdef CONFIG_SELINUX -#include -#include -#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 + * + * 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, "<>") == 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 -#include -#include -#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 +# +# 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 -# -# 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 -# -# 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 -#include #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 -#include -#include #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 - * - * 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 -#include -#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 - * - * 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 * + * 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 -#include -#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 . * - * 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 -#include -#include -#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 * - * 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 " 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef CONFIG_SELINUX -#include -#include -#include +#if ENABLE_FEATURE_ASSUME_UNICODE +#include #endif -#ifdef CONFIG_FEATURE_LS_TIMESTAMPS -#include -#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(¤t_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 */ -/* Hacked to work with BusyBox by Alfred M. Szmidt */ - -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#if defined HAVE_LIMITS_H -# include -#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 , 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 * - * 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 -#include -#include -#include "busybox.h" +/* Nov 28, 2006 Yoshinori Sato : 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 * - * 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 -#include -#include -#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 * - * 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 -#include -#include -#include -#include "busybox.h" +#include // 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 + * SELinux support by Yuichi Nakamura * - * 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 -#include -#include -#include -#include -#include -#include -#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 + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include +#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 + * 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 +nohup: redirecting stderr to stdout +# nohup true 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 -#include -#include -#include -#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 + * Copyright (C) 2005 by Mike Frysinger + * + * 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 */ - + David MacKenzie +*/ // 19990508 Busy Boxed! Dave Cinege -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 . * - * 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 -#include -#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 + * + * 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 -#include -#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 * - * - * 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 -#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 * - * 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 -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* - --------------------------------------------------------------------------- - Begin Dr. Gladman's sha1 code - --------------------------------------------------------------------------- -*/ - -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman , 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 * - * 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 -#include -#include -#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 + * Copyright (C) 2004 by Rob Landley * - * 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 * - * 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 -#include -#include -#include -#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 + * Copyright (C) 2005 by Mike Frysinger + * Copyright (C) 2006 by Yoshinori Sato + * + * 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 at the end */ + /*fputs(b, stdout);*/ + puts(b); + break; + } + *p++ = '\0'; + fputs(b, stdout); + + /* dest = "%" */ + 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 "%" 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 -#include -#include - -#include -#include - -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -#endif - -#ifndef STDOUT_FILENO -# define STDOUT_FILENO 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#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,1170 +109,1331 @@ # 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; +#define CI_ENTRY(n,s,o) n "\0" -/* 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. */ +/* 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 +#ifdef VSWTCH + CI_ENTRY("swtch", CSWTCH, VSWTCH ) +#endif + CI_ENTRY("start", CSTART, VSTART ) + CI_ENTRY("stop", CSTOP, VSTOP ) + CI_ENTRY("susp", CSUSP, VSUSP ) +#ifdef VDSUSP + CI_ENTRY("dsusp", CDSUSP, VDSUSP ) +#endif +#ifdef VREPRINT + CI_ENTRY("rprnt", CRPRNT, VREPRINT) +#endif +#ifdef VWERASE + CI_ENTRY("werase", CWERASE, VWERASE ) +#endif +#ifdef VLNEXT + CI_ENTRY("lnext", CLNEXT, VLNEXT ) +#endif +#ifdef VFLUSHO + CI_ENTRY("flush", CFLUSHO, VFLUSHO ) +#endif +#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 +#ifdef VSWTCH + CI_ENTRY("swtch", CSWTCH, VSWTCH ) +#endif + CI_ENTRY("start", CSTART, VSTART ) + CI_ENTRY("stop", CSTOP, VSTOP ) + CI_ENTRY("susp", CSUSP, VSUSP ) +#ifdef VDSUSP + CI_ENTRY("dsusp", CDSUSP, VDSUSP ) +#endif +#ifdef VREPRINT + CI_ENTRY("rprnt", CRPRNT, VREPRINT) +#endif +#ifdef VWERASE + CI_ENTRY("werase", CWERASE, VWERASE ) +#endif +#ifdef VLNEXT + CI_ENTRY("lnext", CLNEXT, VLNEXT ) +#endif +#ifdef VFLUSHO + CI_ENTRY("flush", CFLUSHO, VFLUSHO ) +#endif +#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 ) +}; -static void wrapf(const char *message, ...) -{ - va_list args; - char buf[1024]; /* Plenty long for our needs. */ - int buflen; +enum { + NUM_control_info = ARRAY_SIZE(control_info) +}; - 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 } +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) -#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; +/* 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; - case 'F': - if (file_name) - bb_error_msg_and_die("only one device may be specified"); - file_name = optarg; - break; + if (ch == _POSIX_VDISABLE) + return ""; - default: /* unrecognized option */ - noargs = 0; - break; - } + if (ch >= 128) { + ch -= 128; + *bpout++ = 'M'; + *bpout++ = '-'; + } - if (noargs == 0) - break; + if (ch < 32) { + *bpout++ = '^'; + *bpout++ = ch + 64; + } else if (ch < 127) { + *bpout++ = ch; + } else { + *bpout++ = '^'; + *bpout++ = '?'; } - if (optind < argc) - noargs = 0; + *bpout = '\0'; + return G.buf; +} - /* 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"); +static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode) +{ + 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 */ + }; - /* 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"); + if (type <= local) { + return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]); + } + return NULL; +} - /* 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. */ +static void set_speed_or_die(enum speed_setting type, const char *const arg, + struct termios * const mode) +{ + speed_t baud; - if (file_name) { - int fdflags; + baud = tty_value_to_baud(xatou(arg)); - 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; + if (type != output_speed) { /* either input or both */ + cfsetispeed(mode, baud); } - - /* 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; + if (type != input_speed) { /* either output or both */ + cfsetospeed(mode, baud); } +} - 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; - } +static NORETURN void perror_on_device_and_die(const char *fmt) +{ + bb_perror_msg_and_die(fmt, G.device_name); +} - 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; - } +static void perror_on_device(const char *fmt) +{ + bb_perror_msg(fmt, G.device_name); +} - 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; +/* 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_error_msg_and_die("invalid argument `%s'", argv[k]); + bb_putchar(' '); } } + fputs(buf, stdout); + G.current_col += buflen; + if (buf[buflen-1] == '\n') + G.current_col = 0; +} - if (require_set_attr) { - struct termios new_mode; - - if (tcsetattr(fd, TCSADRAIN, &mode)) - perror_on_device("%s"); +static void set_window_size(const int rows, const int cols) +{ + struct winsize win = { 0, 0, 0, 0 }; - /* 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. */ + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) { + if (errno != EINVAL) { + goto bail; + } + memset(&win, 0, sizeof(win)); + } - /* 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"); + if (rows >= 0) + win.ws_row = rows; + if (cols >= 0) + win.ws_col = cols; - /* 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 (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win)) +bail: + perror_on_device("%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. */ +static void display_window_size(const int fancy) +{ + const char *fmt_str = "%s\0%s: no size information for this device"; + unsigned width, height; - new_mode.c_cflag &= (~CIBAUD); - if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) -#endif - perror_on_device ("%s: unable to perform all requested operations"); + 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", + height, width); } - - return EXIT_SUCCESS; } -/* Return 0 if not applied because not reversible; otherwise return 1. */ +static const struct suffix_mult stty_suffixes[] = { + { "b", 512 }, + { "k", 1024 }, + { "B", 1024 }, + { } +}; -static int -set_mode(const struct mode_info *info, int reversed, struct termios *mode) +static const struct mode_info *find_mode(const char *name) { - tcflag_t *bitsp; + int i = index_in_strings(mode_name, name); + return i >= 0 ? &mode_info[i] : NULL; +} + +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; +} - if (reversed && (info->flags & REV) == 0) +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, +}; + +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; +} - bitsp = mode_type_flag(info->type, mode); +static int recover_mode(const char *arg, struct termios *mode) +{ + int i, n; + unsigned chr; + unsigned long iflag, oflag, cflag, lflag; - 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 -#endif - ) -#ifdef OCRNL - & ~OCRNL -#endif -#ifdef ONLRET - & ~ONLRET -#endif - ; - } else { - mode->c_iflag = mode->c_iflag & ~ICRNL; -#ifdef ONLCR - mode->c_oflag = mode->c_oflag & ~ONLCR; -#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; -#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 -#ifdef XCASE - | XCASE -#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; - } -#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 -#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; - } - } -#endif - else if (info->name == stty_crt) - mode->c_lflag |= ECHOE -#ifdef ECHOCTL - | ECHOCTL -#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 -#endif -#ifdef ECHOKE - | ECHOKE -#endif - ; -#ifdef IXANY - mode->c_iflag &= ~IXANY; -#endif - } - } else if (reversed) - *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits; - else - *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits; - - return 1; -} - -static void -set_control_char(const struct control_info *info, const char *arg, - struct termios *mode) -{ - unsigned char value; - - 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; -} - -static void -set_speed(enum speed_setting type, const char *arg, struct termios *mode) -{ - speed_t baud; - - baud = string_to_baud(arg); - - if (type != output_speed) { /* either input or both */ - cfsetispeed(mode, baud); - } - if (type != input_speed) { /* either output or both */ - cfsetospeed(mode, baud); - } -} - -#ifdef TIOCGWINSZ - -static int get_win_size(int fd, struct winsize *win) -{ - int err = ioctl(fd, TIOCGWINSZ, (char *) win); - - return err; -} - -static void -set_window_size(int rows, int cols, int fd) -{ - struct winsize win; - - if (get_win_size(fd, &win)) { - if (errno != EINVAL) - perror_on_device("%s"); - memset(&win, 0, sizeof(win)); - } - - if (rows >= 0) - win.ws_row = rows; - if (cols >= 0) - win.ws_col = cols; - -# ifdef TIOCSSIZE - /* Alexander Dupuy 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; + /* 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; } -# endif - - if (ioctl(fd, TIOCSWINSZ, (char *) &win)) - perror_on_device("%s"); -} -static void display_window_size(int fancy, int fd) -{ - const char *fmt_str = "%s" "\0" "%s: no size information for this device"; - struct winsize win; + /* Fail if there are too many fields */ + if (*arg != '\0') + return 0; - if (get_win_size(fd, &win)) { - 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; - } + return 1; } -#endif -static int screen_columns(void) +static void display_recoverable(const struct termios *mode, + int UNUSED_PARAM dummy) { - int columns; - const char *s; - -#ifdef TIOCGWINSZ - struct winsize win; - - /* 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 - - columns = 80; - if ((s = getenv("COLUMNS"))) { - columns = atoi(s); - } - return columns; + 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]); + bb_putchar('\n'); } -static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode) +static void display_speed(const struct termios *mode, int fancy) { - 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 */ - }; + //01234567 8 9 + const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;"; + unsigned long ispeed, ospeed; - if (((unsigned int) type) <= local) { - return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]); + 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;"; } - return NULL; + if (fancy) fmt_str += 9; + wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); } -static void display_changed(struct termios *mode, int fd) +static void do_display(const struct termios *mode, const int all) { int i; - int empty_line; tcflag_t *bitsp; unsigned long mask; - enum mode_type prev_type = control; + int prev_type = control; display_speed(mode, 1); + 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; - 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. */ + 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 - - empty_line = 0; - wrapf("%s = %s;", control_info[i].name, + wrapf("%s = %s;", nth_string(control_name, i), 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; +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0) +#endif + wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); + 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) { - if (empty_line == 0) { - putchar('\n'); - current_col = 0; - empty_line = 1; - } + /* 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) { - if (mode_info[i].flags & SANE_UNSET) { - wrapf("%s", mode_info[i].name); - empty_line = 0; + 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)); } } - else if ((mode_info[i].flags & (SANE_SET | REV)) == - (SANE_SET | REV)) { - wrapf("-%s", mode_info[i].name); - empty_line = 0; - } } - if (empty_line == 0) - putchar('\n'); - current_col = 0; + if (G.current_col) wrapf("\n"); } -static void -display_all(struct termios *mode, int fd) +static void sane_mode(struct termios *mode) { int i; tcflag_t *bitsp; - unsigned long mask; - enum mode_type prev_type = control; - - display_speed(mode, 1); -#ifdef TIOCGWINSZ - display_window_size(1, fd); -#endif -#ifdef HAVE_C_LINE - wrapf("line = %d;", mode->c_line); -#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. */ -#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; + for (i = 0; i < NUM_control_info; ++i) { +#if VMIN == VEOF + if (i == CIDX_min) + break; #endif - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); + mode->c_cc[control_info[i].offset] = control_info[i].saneval; } -#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; 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; - prev_type = mode_info[i].type; + if (mode_info[i].flags & SANE_SET) { + bitsp = mode_type_flag(mode_info[i].type, mode); + *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) + | mode_info[i].bits; + } else if (mode_info[i].flags & SANE_UNSET) { + bitsp = mode_type_flag(mode_info[i].type, mode); + *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) + & ~mode_info[i].bits; } - - 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) +/* 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 void set_mode(const struct mode_info *info, int reversed, + struct termios *mode) { - 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;"; + tcflag_t *bitsp; - ospeed = ispeed = cfgetispeed(mode); - if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) { - ispeed = ospeed; /* in case ispeed was 0 */ - fmt_str += 43; + bitsp = mode_type_flag(info->type, mode); + + if (bitsp) { + if (reversed) + *bitsp = *bitsp & ~info->mask & ~info->bits; + else + *bitsp = (*bitsp & ~info->mask) | info->bits; + return; } - if (fancy) { - fmt_str += 9; + + /* 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; } - 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) +static void set_control_char_or_die(const struct control_info *info, + const char *arg, struct termios *mode) { - int i; + unsigned char value; - 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'); + 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; } -static int recover_mode(char *arg, struct termios *mode) +#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) { - int i, n; - unsigned int chr; - unsigned long iflag, oflag, cflag, lflag; + 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; - /* 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; - } + INIT_G(); - /* Fail if there are too many fields. */ - if (*arg != '\0') - return 0; + stty_state = STTY_noargs; + output_func = do_display; - return 1; -} + /* 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; + } -static speed_t string_to_baud(const char *arg) -{ - return bb_value_to_baud(bb_xparse_number(arg, 0)); -} + mp = find_mode(arg); + if (mp) { + stty_state &= ~STTY_noargs; + continue; + } -static void sane_mode(struct termios *mode) -{ - int i; - tcflag_t *bitsp; + 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; + } - for (i = 0; i < NUM_control_info; ++i) { -#if VMIN == VEOF - if (control_info[i].name == stty_min) + 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 - mode->c_cc[control_info[i].offset] = control_info[i].saneval; +#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; } - for (i = 0; i < NUM_mode_info; ++i) { - if (mode_info[i].flags & SANE_SET) { - bitsp = mode_type_flag(mode_info[i].type, mode); - *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) - | mode_info[i].bits; - } else if (mode_info[i].flags & SANE_UNSET) { - bitsp = mode_type_flag(mode_info[i].type, mode); - *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) - & ~mode_info[i].bits; + /* 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"); } -} - -/* Return a string that is the printable representation of character CH. */ -/* Adapted from `cat' by Torbjorn Granlund. */ -static const char *visible(unsigned int ch) -{ - static char buf[10]; - char *bpout = buf; + /* 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 (ch == _POSIX_VDISABLE) { - return ""; + 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; } - if (ch >= 128) { - ch -= 128; - *bpout++ = 'M'; - *bpout++ = '-'; - } + /* 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; + } - if (ch < 32) { - *bpout++ = '^'; - *bpout++ = ch + 64; - } else if (ch < 127) { - *bpout++ = ch; - } else { - *bpout++ = '^'; - *bpout++ = '?'; + 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); */ + } } - *bpout = '\0'; - return (const char *) buf; -} + if (stty_state & STTY_require_set_attr) { + struct termios new_mode; -#ifdef TEST + if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) + perror_on_device_and_die("%s"); -const char *bb_applet_name = "stty"; + /* 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 + * Copyright (C) 2005 by Mike Frysinger + * + * 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 . * - * 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 -#include -#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 + * Copyright (C) 2007 Natanael Copa + * Copyright (C) 2007 Tito Ragusa + * + * 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 * - * 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 -#include -#include -#include -#include -#include -#include -#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 * - * 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 -#include -#include -#include -#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 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 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 -#include -#include -#include -#include -#include -#include "busybox.h" +#include "libbb.h" +#include + +/* 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 ::= */ +#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(" 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("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("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("op_type == BINOP) + unnest_msg_and_return(binop(), "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', "op_type == BINOP) { + /* args[2] is known to be NULL, isn't it bound to fail? */ + unnest_msg_and_return(binop(), "op_type == BINOP) { + /* "test [!] arg1 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 + * + * 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 - * - * 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 * + * 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 -#include -#include -#include -#include -#include -#include -#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 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 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 -#include -#include -#include -#include -#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 - * - * 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 * + * 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 -#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 * - * 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 -#include -#include -#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 + * + * 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 */ - -/* 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 -#include -#include -#include -#include -#include #include -#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 - * - * 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 * + * 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 -#include -#include -#include -#include -#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 * - * 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 -#include -#include -#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 -#include -#include -#include -#include -#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. - * - * 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 -#include -#include -#include -#include -#include -#include -#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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#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 * - * 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 -#include -#include -#include -#include "busybox.h" +#include "libbb.h" -#ifdef CONFIG_LOCALE_SUPPORT -#include -#include +#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 @@ -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 -#include -#include -#include +#include "libbb.h" #include -#include -#include -#include -#include -#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 . * - * 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 -#include -#include -#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 * - * 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 -#include -#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(); -- cgit v1.2.3-54-g00ecf